256

uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências
Page 2: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências
Page 3: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

EstaapostiladaCaelumvisaensinardeumamaneiraelegante,mostrandoapenasoqueénecessárioequandoénecessário,nomomentocerto,poupandoo leitordeassuntosquenãocostumamserde seuinteresseemdeterminadasfasesdoaprendizado.

ACaelumesperaquevocêaproveiteessematerial.Todososcomentários,críticasesugestõesserãomuitobem-vindos.

EssaapostilaéconstantementeatualizadaedisponibilizadanositedaCaelum.Sempreconsulteositeparanovasversõese,aoinvésdeanexaroPDFparaenviaraumamigo,indiqueositeparaqueelepossasemprebaixarasúltimasversões.Vocêpodeconferirocódigodeversãodaapostilalogono naldoíndice.

Baixesempreaversãomaisnovaem:www.caelum.com.br/apostilas

Esse material é parte integrante do treinamento Java para Desenvolvimento Web e distribuídogratuitamente exclusivamente pelo site da Caelum. Todos os direitos são reservados à Caelum. Adistribuição, cópia, revenda e utilização paraministrar treinamentos são absolutamente vedadas. Parausocomercialdestematerial,porfavor,consulteaCaelumpreviamente.

SOBREESTAAPOSTILA

Page 4: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1

3

32

Sumário

1EnfrentandooJavanaWeb1.1OgrandemercadodoJavanaWeb 1

1.2Livrosesitesinteressantes 2

2BancosdedadoseJDBC2.1Porqueusarumbancodedados? 3

2.2PersistindoatravésdeSockets? 4

2.3AconexãoemJava 4

2.4FábricadeConexões 7

2.5DesignPatterns 9

2.6Exercícios:ConnectionFactory 10

2.7AtabelaContato 14

2.8Javabeans 15

2.9Inserindodadosnobanco 16

2.10DAO-DataAccessObject 20

2.11Exercícios:JavabeanseContatoDao 22

2.12Fazendopesquisasnobancodedados 25

2.13Exercícios:Listagem 27

2.14Umpoucomais... 28

2.15Exercíciosopcionais 29

2.16OutrosmétodosparaoseuDAO 29

2.17Exercíciosopcionais-Alterareremover 30

3OqueéJavaEE?3.1ComooJavaEEpodeteajudaraenfrentarproblemas 32

3.2AlgumasespecificaçõesdoJavaEE 34

3.3ServidordeAplicação 34

3.4ServletContainer 35

3.5Exercícios:PreparandooTomcat 36

3.6PreparandooTomcatemcasa 37

SumárioCaelum

Page 5: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

44

56

82

3.7Outraopção:Jetty 38

3.8IntegrandooTomcatnoEclipse 39

3.9OpluginWTP 39

3.10Exercícios:ConfigurandooTomcatnoEclipse 40

4NovoprojetoWebusandoEclipse4.1Novoprojeto 44

4.2Exercícios:Novoprojetoweb 44

4.3Análisedoresultadofinal 48

4.4CriandonossaspáginaseHTMLBásico 52

4.5Exercícios:primeirapágina 53

4.6Parasabermais:configurandooTomcatsemoplugin 53

4.7AlgumastagsHTML 54

5Servlets5.1Páginasdinâmicas 56

5.2Servlets 57

5.3Mapeandoumaservletnoweb.xml 59

5.4Aestruturadediretórios 60

5.5Exercícios:PrimeiraServlet 61

5.6Erroscomuns 64

5.7FacilidadesdasServlets3.0 65

5.8Parasabermais:WebServleteInitParamAnnotation 67

5.9Enviandoparâmetrosnarequisição 68

5.10Pegandoosparâmetrosdarequisição 69

5.11Exercícios:Criandofuncionalidadeparagravarcontatos 71

5.12GET,POSTemétodosHTTP 75

5.13TratandoexceçõesdentrodaServlet 75

5.14Exercício:TratandoexceçõesecódigosHTTP 77

5.15IniteDestroy 78

5.16UmaúnicainstânciadecadaServlet 79

5.17Exercíciosopcionais 81

5.18Discussão:Criandopáginasdentrodeumaservlet 81

6JavaServerPages6.1ColocandooHTMLnoseudevidolugar 82

6.2Exercícios:PrimeiroJSP 84

6.3ListandooscontatoscomScriptlet 85

6.4Exercíciosopcionais:Listadecontatoscomscriptlet 86

CaelumSumário

Page 6: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

90

107

116

6.5MisturandocódigoJavacomHTML 87

6.6EL:Expressionlanguage 88

6.7Exercícios:parâmetroscomaExpressionLanguage 88

6.8Parasabermais:CompilandoosarquivosJSP 89

7UsandoTaglibs7.1Taglibs 90

7.2InstanciandoPOJOs 91

7.3JSTL 92

7.4Instalação 92

7.5CabeçalhoparaaJSTLcore 93

7.6ForEach 93

7.7Exercícios:forEach 95

7.8Exercíciosopcionais 96

7.9Evoluindonossalistagem 97

7.10FazendoifscomaJSTL 97

7.11Exercícios:listadecontatoscomcondicionais 98

7.12Importandopáginas 99

7.13Exercícios:cabeçalhoserodapés 100

7.14Formataçãodedatas 102

7.15Exercícios:Formatandoadatadenascimentodoscontatos 103

7.16Parasabermais:linkscom<c:url> 104

7.17Exercíciosopcionais:Caminhoabsoluto 105

7.18Parasabermais:Outrastags 105

8TagscustomizadascomTagfiles8.1PorqueeuprecisariadeoutrastagsalémdaJSTL? 107

8.2CalendárioscomjQuery 108

8.3CriandominhasprópriastagscomTagfiles 109

8.4Exercícios:criandonossaprópriatagparacalendário 111

8.5Parasabermais:Outrastaglibsnomercado 114

8.6Desafio:Colocandodisplaytagnoprojeto 115

9MVC-ModelViewController9.1ServletouJSP? 116

9.2RequestDispatcher 118

9.3Exercícios:RequestDispatcher 119

9.4Melhorandooprocesso 120

9.5RetomandoodesignpatternFactory 124

SumárioCaelum

Page 7: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

133

146

9.6Exercícios:Criandonossaslógicaseaservletdecontrole 125

9.7Exercícios:Criandoumalógicapararemovercontatos 126

9.8Fazendoalógicaparalistaroscontatos 127

9.9Exercícios:Lógicaparalistarcontatos 128

9.10Escondendonossaspáginas 129

9.11Exercíciosopcionais 130

9.12ModelViewController 131

9.13Listadetecnologias:camadadecontrole 131

9.14Listadetecnologias:camadadevisualização 132

9.15Discussãoemaula:ospadrõesCommandeFrontController 132

10Recursosimportantes:Filtros10.1ReduzindooacoplamentocomFiltros 141

10.2Exercíciosopcionais:Filtroparamedirotempodeexecução 138

10.3Problemasnacriaçãodasconexões 139

10.4Tentandooutrasestratégias 140

10.5ReduzindooacoplamentocomFiltros 141

10.6Exercícios:Filtros 144

11SpringMVC11.1PorqueprecisamosdeframeworksMVC? 146

11.2Umpoucodehistória 147

11.3ConfigurandooSpringMVC 148

11.4Criandoaslógicas 150

11.5AlógicaOláMundo! 150

11.6Parasabermais:ConfigurandooSpringMVCemcasa 152

11.7Exercícios:ConfigurandooSpringMVCetestandoaconfiguração 152

11.8Adicionandotarefasepassandoparâmetros 154

11.9Exercícios:Criandotarefas 157

11.10Incluindovalidaçãonocadastrodetarefas 160

11.11ValidaçãocomBeanValidation 161

11.12Exercícios:Validandotarefas 163

11.13Listandoastarefasedisponibilizandoobjetosparaaview 165

11.14Exercícios:Listandotarefas 166

11.15Redirecionandoarequisiçãoparaoutraação 168

11.16Exercícios:Removendoealterandotarefas 169

11.17Desafio-Calendário 171

11.18Melhorandoausabilidadedanossaaplicação 171

11.19UtilizandoAJAXparamarcartarefascomofinalizadas 173

CaelumSumário

Page 8: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

182

191

207

11.20ConfiguraroSpringMVCparaacessararquivoscomuns 174

11.21Exercícios:Ajax 175

11.22Parasabermais:AlterandovalordadatacomAJAX 177

11.23ExercíciosOpcionais:MelhorandonossoAJAX 180

12SpringMVC:Autenticaçãoeautorização12.1Autenticandousuários:comofunciona? 182

12.2Cookies 182

12.3Sessão 183

12.4Configurandootempolimite 183

12.5Registrandoousuáriologadonasessão 184

12.6Exercício:Fazendoologinnaaplicação 185

12.7BloqueandoacessosdeusuáriosnãologadoscomInterceptadores 186

12.8Exercícios:Interceptandoasrequisições 188

12.9Exercíciosopcionais:Logout 189

13SpringIoCedeploydaaplicação13.1Menosacoplamentocominversãodecontroleeinjeçãodedependências 191

13.2ContainerdeInjeçãodedependências 194

13.3ContainerSpringIoC 195

13.4Outrasformasdeinjeção 197

13.5Exercícios:InversãodecontrolecomoSpringContainer 198

13.6AprimorandoovisualatravésdeCSS 200

13.7Exercíciosopcionais:AplicandoCSSnaspáginas 202

13.8Deploydoprojetoemoutrosambientes 203

13.9Exercícios:Deploycomwar 204

13.10Discussãoemaula:lidandocomdiferentesnomesdecontexto 206

14UmaintroduçãopráticaaoJPAcomHibernate14.1MapeamentoObjetoRelacional 207

14.2JavaPersistenceAPIeFrameworksORM 208

14.3BibliotecasdoHibernateeJPA 208

14.4MapeandoumaclasseTarefaparanossoBancodeDados 209

14.5ConfigurandooJPAcomaspropriedadesdobanco 211

14.6UsandooJPA 212

14.7Parasabermais:ConfigurandooJPAcomHibernateemcasa 212

14.8Exercícios:ConfigurandooJPAegerandooschemadobanco 213

14.9Trabalhandocomosobjetos:oEntityManager 216

14.10Exercícios:GravandoeCarregandoobjetos 217

SumárioCaelum

Page 9: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

222

225

239

14.11Removendoeatualizandoobjeto 219

14.12Buscandocomumacláusulawhere 219

14.13Exercícios:BuscandocomJPQL 220

15Eagora?15.1Osapêndicesdessaapostila 222

15.2FrameworksWeb 222

15.3Frameworksdepersistência 223

15.4Ondeseguirseusestudos 224

16Apêndice-IntegraçãodoSpringcomJPA16.1GerenciandooEntityManager 225

16.2ConfigurandooJPAnoSpring 226

16.3InjetandooEntityManager 227

16.4Baixoacoplamentopelousodeinterface 228

16.5Gerenciandoatransação 230

16.6Exercícios:IntegrandoJPAcomSpring 232

16.7ExercíciosOpcionais:IntegrandoaentidadeUsercomoJPA 235

17Apêndice-TópicosdaServletAPI17.1Init-paramsecontext-params 239

17.2welcome-file-list 240

17.3PropriedadesdepáginasJSP 240

17.4Inclusãoestáticadearquivos 241

17.5TratamentodeerroemJSP 242

17.6Descobrindotodososparâmetrosdorequest 243

17.7Trabalhandocomlinkscomac:url 243

17.8Contextlistener 244

17.9OServletContexteoescopodeaplicação 244

17.10Outroslisteners 246

Versão:25.1.6

CaelumSumário

Page 10: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO1

"Todohomemtemalgumaslembrançasqueelenãocontaatodomundo,masapenasaseusamigos.Eletem outras lembranças que ele não revelaria nem mesmo para seus amigos, mas apenas para elemesmo,efazissoemsegredo.Masaindaháoutraslembrançasqueohomemtemmedodecontaratéaelemesmo,etodohomemdecentetemumconsiderávelnúmerodessascoisasguardadasbemnofundo.Alguématépoderiadizerque,quantomaisdecenteéohomem,maioronúmerodessascoisasemsuamente."--FiodórDostoiévski,emMemóriasdoSubsolo

ComofazeraplataformaJavaeaWebtrabalharemjuntas?

CertamenteomercadocommaisoportunidadesemqueoJavaestápresenteéodeWeb.Nãoéporacasosuapopularidade:criarumprojetocomJavadámuitaliberdade,evitandocairnovendorlock-in.Em outras palavras, sua empresa fica independente do fabricante de vários softwares: do servletcontainer,dobancodedadoseatédaprópriafabricantedasuaVirtualMachine!Alémdisso,podemosfazertodoodesenvolvimentoemumsistemaoperacionalefazerodeploy(implantação)emoutro.

Apesar de tanta popularidade no ambiente Web, o desenvolvimento com Java não é trivial: énecessárioconhecercomcertaprofundidadeasAPIsdeservletsedeJSP,mesmoquesuaequipevenhautilizar frameworkscomoStruts,VRaptorouJSF.ConceitosdeHTTP,sessionecookies tambémsãomandatóriosparapoderenxergargargaloseproblemasquesuaaplicaçãoenfrentará.

Essecursoabordadesdeobancodedados,atéousode frameworksMVCparadesacoplaro seucódigo. Ao final do curso, ainda veremos o SpringMVC e o Hibernate, duas das ferramentasmaispopularesentreosrequisitosnasmuitasvagasdeempregoparadesenvolvedorWeb.

Por fim, faltamencionar sobre aprática, quedeve ser tratada seriamente: todosos exercícios sãomuito importantes e os desafios podem ser feitos quando o curso acabar. De qualquer maneira,recomendamosaosalunosestudaremcasa,principalmenteàquelesquefazemoscursosintensivos.

Como estudaremos várias tecnologias e ambientes, é comum esbarrarmos em algum erro que setorneumimpeditivoparaprosseguirnosexercícios,portantonãodesanime.

Lembre-se de usar o fórum do GUJ (http://www.guj.com.br/), onde sua dúvida será respondidaprontamente.Vocêtambémpodeentraremcontatocomseuinstrutorparatirardúvidasdurantetodoo

ENFRENTANDOOJAVANAWEB

1.1OGRANDEMERCADODOJAVANAWEB

1ENFRENTANDOOJAVANAWEB 1

Page 11: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

seucurso.

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

É possível aprender muitos dos detalhes e pontos não cobertos no treinamento em tutoriais naInternetemportaiscomooGUJ,emblogseemmuitossitesespecializados.

http://www.guj.com.br/

AeditoraCasadoCódigopossui livrosdeJava,comodeAndroid,JSFeJPA,evendee-booksapreçosbastantejustos:

http://www.CasaDoCodigo.com.br/

Não deixe de conhecer os outros cursos daCaelum, inclusive os novos cursos online, onde vocêpodecomeçaraestudaragoramesmo.

http://www.alura.com.br/

Seuslivrosdetecnologiaparecemdoséculopassado?

1.2LIVROSESITESINTERESSANTES

2 1.2LIVROSESITESINTERESSANTES

Page 12: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO2

"Omedoéopaidamoralidade"--FriedrichWilhelmNietzsche

Aotérminodessecapítulo,vocêserácapazde:

conectar-seaumbancodedadosqualqueratravésdaAPIJDBC;criarumafábricadeconexõesusandoodesignpatternFactory;pesquisardadosatravésdequeries;encapsularsuasoperaçõescombancosdedadosatravésdeDAO-DataAccessObject.

Muitos sistemas precisam manter as informações com as quais eles trabalham para permitirconsultas futuras,geraçãoderelatóriosoupossíveisalteraçõesnas informações.Paraqueessesdadossejammantidospara sempre, esses sistemasgeralmenteguardamessas informações emumbancodedados,queasmantémdeformaorganizadaeprontasparaconsultas.

A maioria dos bancos de dados comerciais são os chamados relacionais, que é uma forma detrabalharepensardiferenteaoparadigmaorientadoaobjetos.

OMySQLéobancodedadosqueusaremosduranteocurso.Éumdosmaisimportantesbancosdedados relacionais, e é gratuito, além de ter uma instalação fácil para todos os sistemas operacionais.Depoisdeinstalado,paraacessá-loviaterminal,fazemosdaseguinteforma:

mysql-uroot-p

Digitandoasenhaemseguida,casohaja.Seousuáriorootnãotiversenha,ocomandoacimanão

precisado-p.

BANCODEDADOS

Para aqueles que não conhecem um banco de dados, é recomendado ler um pouco sobre oassuntoetambémterumabasedeSQLparacomeçarausaraAPIJDBC.

BANCOSDEDADOSEJDBC

2.1PORQUEUSARUMBANCODEDADOS?

2BANCOSDEDADOSEJDBC 3

Page 13: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

O processo de armazenamento de dados é também chamado de persistência. A biblioteca depersistênciaembancodedadosrelacionaisdoJavaéchamadaJDBC(JavaDataBaseConnectivity),etambémexistemdiversasferramentasdotipoORM(ObjectRelationalMapping)quefacilitambastanteousodoJDBC.Nestemomento, focaremosnosconceitosenousodoJDBC.Veremosumpoucodaferramenta de ORMHibernate ao final destemesmo curso e, no curso FJ-25, commuitos detalhes,recursosetópicosavançados.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

Paraconectar-seaumbancodedados,poderíamosabrirsocketsdiretamentecomoservidorqueohospeda,porexemplo,umOracleouMySQL,enoscomunicarmoscomeleatravésdeseuprotocoloproprietário.

Mas você conhece o protocolo proprietário de algum banco de dados? Conhecer um protocolocomplexoemprofundidadeédifícil,trabalharcomeleémuitotrabalhoso.

Uma segunda ideia seria utilizar umaAPI específica para cada banco de dados.Antigamente, noPHP,porexemplo,aúnicamaneiradeacessaroOracleeraatravésdefunçõescomooracle_connect,

oracle_result,eassimpordiante.OMySQLtinhasuasfunçõesanálogas,comomysql_connect.

Essaabordagemfacilitamuitonossotrabalhopornãoprecisarmosentenderoprotocolodecadabanco,mas fazcomque tenhamosdeconhecerumaAPIumpoucodiferenteparacada tipodebanco.Alémdisso,casoprecisemostrocardebancodedadosumdia,precisaremostrocartodoonossocódigopararefletirafunçãocorretadeacordocomonovobancodedadosqueestamosutilizando.

AconexãoaumbancodedadoséfeitademaneiraelegantecomJava.Paraevitarquecadabanco

EditoraCasadoCódigocomlivrosdeumaformadiferente

2.2PERSISTINDOATRAVÉSDESOCKETS?

2.3ACONEXÃOEMJAVA

4 2.2PERSISTINDOATRAVÉSDESOCKETS?

Page 14: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

tenhaa suaprópriaAPI eumconjuntode classes emétodos, temosumúnicoconjuntode interfacesmuitobemdefinidasquedevemser implementadas.Esseconjuntode interfacesficadentrodopacotejava.sqlenosreferiremosaelecomoJDBC.

Entreasdiversasinterfacesdestepacote,existeainterfaceConnection,quedefinemétodospara

executarumaquery(comouminserteselect),comitartransação,fecharaconexão,entreoutros.

Caso queiramos trabalhar com o MySQL, precisamos de classes concretas que implementem essasinterfacesdopacotejava.sql.

EsseconjuntodeclassesconcretaséquemfaráaponteentreocódigoclientequeusaaAPIJDBCeobancodedados.Sãoessasclassesquesabemsecomunicaratravésdoprotocoloproprietáriodobancodedados.Esseconjuntodeclassesrecebeonomededriver.TodososprincipaisbancosdedadosdomercadopossuemdriversJDBCparaquevocêpossautilizá-loscomJava.Onomedriveréanálogoaoqueusamosparaimpressoras:comoéimpossívelqueumsistemaoperacionalsaibaconversarcomtodotipodeimpressoraexistente,precisamosdeumdriverquefaçaopapelde"tradutor"dessaconversa.

Para abrir uma conexão comumbancode dados, precisamos utilizar sempre umdriver.A classeDriverManageréaresponsávelporsecomunicarcomtodososdriversquevocêdeixoudisponível.

Paraisso,invocamosométodoestáticogetConnectioncomumaStringque indicaaqualbanco

desejamosnosconectar.

EssaString -chamadadeStringdeconexãoJDBC -queutilizaremosparaacessaroMySQL

temsempreaseguinteforma:

jdbc:mysql://ip/nome_do_banco

2.3ACONEXÃOEMJAVA 5

Page 15: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

DevemossubstituirippeloIPdamáquinadoservidorenome_do_bancopelonomedobancode

dadosaserutilizado.

Seguindooexemploda linhaacimae tudoque foiditoatéagora, seriapossível rodaroexemploabaixoereceberumaconexãoparaumbancoMySQL,casoeleestejarodandonamesmamáquina:

publicclassJDBCExemplo{publicstaticvoidmain(String[]args)throwsSQLException{Connectionconexao=DriverManager.getConnection("jdbc:mysql://localhost/fj21");System.out.println("Conectado!");conexao.close();}}

ReparequeestamosdeixandopassaraSQLException,queéumaexceptionchecked, lançadapor

muitosdosmétodosdaAPIdeJDBC.Numaaplicaçãorealdevemosutilizartry/catchnos lugares

quejulgamoshaverpossibilidadederecuperardeumafalhacomobancodedados.Tambémprecisamostomarsemprecuidadoparafechartodasasconexõesqueforamabertas.

Aotestarocódigoacima,recebemosumaexception.Aconexãonãopôdeseraberta.Recebemosamensagem:

java.sql.SQLException:Nosuitabledriverfoundforjdbc:mysql://localhost/fj21

Porquê?

Osistemaaindanãoachouuma implementaçãodedriverJDBC quepode ser usadapara abrir aconexãoindicadapelaURLjdbc:mysql://localhost/fj21.

O que precisamos fazer é adicionar o driver do MySQL ao classpath, ou seja, o arquivo .jarcontendo a implementação JDBC do MySQL (mysql connector) precisa ser colocado em um lugarvisívelpeloseuprojetoouadicionadoàvariáveldeambienteCLASSPATH.ComousaremosoEclipse,

depoisdeadicionarojardodriverJDBCdoMySQLnapastadoprojeto,faremosissoatravésdeumcliquedadireitaemnossoprojeto,BuildPatheemAddtoBuildPath.Veremosistopassoapassonosexercícios.

6 2.3ACONEXÃOEMJAVA

Page 16: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

EOCLASS.FORNAME?

Atéaversão3doJDBC,antesdechamaroDriverManager.getConnection()eranecessário

registrar o driver JDBC que iria ser utilizado através do métodoClass.forName("com.mysql.jdbc.Driver"),nocasodoMySQL,quecarregavaessaclasse,e

essasecomunicavacomoDriverManager.

ApartirdoJDBC4,queestápresentenoJava6,essepassonãoémaisnecessário.Maslembre-se:casovocêutilizeJDBCemumprojetocomJava5ouanterior,seráprecisofazeroregistrodoDriverJDBC,carregandoasuaclasse,quevaiseregistrarnoDriverManager.

Issotambémpodesernecessárioemalgunsservidoresdeaplicaçãoeweb,comonoTomcat7ouposterior,porproteçãoparapossíveisvazamentosdememória:

http://bit.ly/18BpDfG

Teoricamente,bastaalterarasduasStringsqueescrevemosparamudardeumbancoparaoutro.

Porém,nãoétudotãosimplesassim!OcódigoSQLqueveremosaseguirpodefuncionaremumbanco

enãoemoutros.DependedequãoaderenteaopadrãoANSISQLéseubancodedados.

Isso só causa dor de cabeça e existem projetos que resolvem isso, como é o caso do Hibernate(www.hibernate.org)edaespecificaçãoJPA(JavaPersistenceAPI).VeremosumpoucodoHibernateaofinaldessecursoebastantesobreelenoFJ-25.

Osdriverspodemserbaixadosnormalmentenositedofabricantedobancodedados.

Algunscasos,comonoMicrosoftSQLServer,existemoutrosgruposquedesenvolvemodriveremhttp://jtds.sourceforge.net . Enquanto isso, você pode achar o driver doMYSQL (chamado demysqlconnector)nositehttp://www.mysql.org.

Emdeterminadomomentodenossaaplicação,gostaríamosdeterocontrolesobreaconstruçãodosobjetosdanossaclasse.Muitopodeserfeitoatravésdoconstrutor,comosaberquantosobjetosforaminstanciadosoufazerologsobreessasinstanciações.

Àsvezes, tambémqueremoscontrolarumprocessomuitorepetitivoe trabalhoso,comoabriruma

Alterandoobancodedados

Driversdeoutrosbancosdedados

2.4FÁBRICADECONEXÕES

2.4FÁBRICADECONEXÕES 7

Page 17: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

conexãocomobancodedados.Tomemoscomoexemploaclasseaseguir,queseria responsávelporabrirumaconexãocomobanco:

publicclassConnectionFactory{publicConnectiongetConnection(){try{returnDriverManager.getConnection("jdbc:mysql://localhost/fj21","root","<SENHADOBANCOAQUI>");}catch(SQLExceptione){thrownewRuntimeException(e);}}}

Assim, sempre que quisermos obter uma conexão com o banco no nosso código, usaremos ocomandoaseguir:

Connectioncon=newConnectionFactory().getConnection();

NotequeométodogetConnection()éumafábricadeconexões,istoé,elecrianovasconexões

paranós.Bastainvocarométodoerecebemosumaconexãoprontaparauso,nãoimportandodeondeelaveioeeventuaisdetalhesdecriação.Portanto,vamoschamaraclassedeConnectionFactoryeo

métododegetConnection.

Encapsulandodessaforma,podemosmaistardemudaraobtençãodeconexões,para,porexemplo,usarummecanismodepooling,queéfortementerecomendávelemumaaplicaçãoreal.

TRATAMENTODEEXCEÇÕES

Reparequeestamosfazendoumtry/catchemSQLException e relançando-a comouma

RuntimeException.Fazemosissoparaqueoseucódigoquechamaráafábricadeconexõesnão

fiqueacopladocomaAPIdeJDBC.TodavezquetivermosquelidarcomumaSQLException,

vamosrelançá-lascomoRuntimeException.

PoderíamosaindacriarnossaprópriaexceçãoparaindicarqueocorreuumerrodentrodanossaFactory,algocomoumaConnectionFactoryException.

8 2.4FÁBRICADECONEXÕES

Page 18: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

Orientaçãoaobjetosresolveasgrandesdoresdecabeçaquetínhamosnaprogramaçãoprocedural,restringindoecentralizandoresponsabilidades.

Masalgunsproblemasnãopodemosresolversimplesmentecomorientaçãoaobjetos,poisnãoexistepalavrachaveparaumafuncionalidadetãoespecífica.

Algunsdessespequenosproblemasaparecemcomtantafrequênciaqueaspessoasdesenvolvemumasolução"padrão"paraele.Comisso,aonosdefrontarmoscomumdessesproblemasclássicos,podemosrapidamente implementaressasoluçãogenéricacomumaououtramodificação,deacordocomnossanecessidade.EssassoluçõespadrõestemonomedeDesignPatterns(PadrõesdeProjeto).

AmelhormaneiraparaaprenderoqueéumDesignPatternévendocomosurgiusuanecessidade.

AnossaConnectionFactoryimplementaodesignpatternFactory,quepregaoencapsulamento

daconstrução(fabricação)deobjetoscomplicados.

ABÍBLIADOSDESIGNPATTERNS

OlivromaisconhecidodeDesignPatterns foi escritoem1995e tem trechosdecódigoemC++eSmalltalk.Masoquerealmenteimportasãoosconceitoseosdiagramasquefazemdesselivroindependentedequalquerlinguagem.Alémdetudo,olivroédeleituraagradável.

DesignPatterns,ErichGammaetal.

JáconheceoscursosonlineAlura?

2.5DESIGNPATTERNS

2.5DESIGNPATTERNS 9

Page 19: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. NoscomputadoresdaCaelum,cliquenoíconedoEclipsenoDesktop;

BAIXANDOOECLIPSEEMCASA

Estamos usando o Eclipse for Java EEDevelopers. Você pode obtê-lo direto no site doEclipseemwww.eclipse.org

FecheateladeWelcomecasoelaapareça

VamoscriarumprojetonoEclipsechamadofj21-jdbc.

VáemFile->New->Project:

SelecioneJavaProjectecliqueemNext:

2.6EXERCÍCIOS:CONNECTIONFACTORY

10 2.6EXERCÍCIOS:CONNECTIONFACTORY

Page 20: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Coloqueonomedoprojetocomofj21-jdbcecliqueemFinish:

Umanova janela surgiráperguntandosevocêquercriarumnovomodule-info.java,cliqueemDon'tCreate

Aceiteamudançadeperspectiva:

2.6EXERCÍCIOS:CONNECTIONFACTORY 11

Page 21: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

2. CopieodriverdoMySQLparaoseuprojeto.

noseuDesktop,cliquenoatalhoAtalhoparaarquivosdocursos;copieapasta21paraoseuDesktop;entrenapasta21/projeto-jdbc/mysqldoDesktop,cliquecomobotãodireitodomousenodriverdoMySQLecopie;váparasuapastaprincipal(home);

entrenodiretórioworkspace,fj21-jdbc;

cliquecomobotãodireitodomouseecoleodriveraqui:vocêacabadecolocaroarquivo".jar"noseuprojeto.

3. Vamoscriaraclassequefabricaconexões:

CliqueemFile->New->Class.

Crie-anopacotebr.com.caelum.jdbcenomeie-acomoConnectionFactory.

CliqueemFinish

Nocódigo,crieométodogetConnection,queretornaumanovaconexão.Quandoperguntado,

importeasclassesdopacotejava.sql(cuidadoparanãoimportarNADAdecom.mysql).

PresteatençãoaosparâmetrosdométodogetConnection, o último é a senhadousuárioque

estamosusando,nocasooroot.Esseusuárioestáconfiguradocomasenha""(aspasvazias).

publicConnectiongetConnection(){try{returnDriverManager.getConnection("jdbc:mysql://localhost/fj21","root","");}catch(SQLExceptione){thrownewRuntimeException(e);}}

12 2.6EXERCÍCIOS:CONNECTIONFACTORY

Page 22: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. CrieumaclassechamadaTestaConexaonopacotebr.com.caelum.jdbc.teste.Todasasnossas

classesdetestedeverãoficarnessepacote.

Crieummétodomaindentrodaclasse.UseoatalhodoEclipseparaajudar.

Dentrodomain, fabriqueuma conexãousando aConnectionFactory que criamos.Vamos

apenastestaraaberturadaconexãoedepoisfechá-lacomométodoclose:

Connectionconnection=newConnectionFactory().getConnection();System.out.println("Conexãoaberta!");connection.close();

Trateoserroscomthrows.(Use:Ctrl+1eescolha"addthrowsdeclaration").

1. AntesdetestaraconexãocomobancodedadosatravésdaclasseTestaConexao,verifiqueseo

bancodedadosfj21existe.

Abraoterminaledigite:

mysql-uroot

Lembrandoque,sehouversenhaparalogarcomobanco,éprecisoescrevermysql-uroot-pe,

emseguida,digitarasenhadobancodedados.

DentrodoMySQL,procurepelobancodedadosfj21comocomando:

showdatabases;

Seelenãoexistir,criecomocomando:

createdatabasefj21;

1. RodeasuaclasseTestaConexaopeloEclipse.

CliquedadireitanasuaclasseTestaConexao

EscolhaRun as, Java Application (caso prefira, aprenda a tecla de atalho para agilizar naspróximasexecuções)

2. A aplicação não funciona pois o driver não foi encontrado? Esquecemos de colocar o JAR no

2.6EXERCÍCIOS:CONNECTIONFACTORY 13

Page 23: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

classpath!(BuildPathnoEclipse)

CliquenoseuprojetocomobotãodadireitaeescolhaRefresh(oupressioneF5).SelecioneoseudriverdoMySQL,cliquedadireitaeescolhaBuildPath,AddtoBuildPath:

RodenovamentesuaaplicaçãoTestaConexaoagoraquecolocamosodrivernoclasspath.

Paracriarumatabelanova,primeirodevemosacessaroterminalefazerocomandoparalogarmosnomysql:

mysql-uroot

senãohouversenha,ou

mysql-uroot-p

sehouver,digitandoemseguidaasenha,queoinstrutordiráqualé.

Nospreparamosparausarobancodedadosfj21:

usefj21;

Aseguintetabelaseráusadanosexemplosdessecapítulo:

createtablecontatos(idBIGINTNOTNULLAUTO_INCREMENT,nomeVARCHAR(255),emailVARCHAR(255),enderecoVARCHAR(255),dataNascimentoDATE,primarykey(id));

No banco de dados relacional, é comum representar um contato (entidade) em uma tabela decontatos.

2.7ATABELACONTATO

14 2.7ATABELACONTATO

Page 24: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

OquesãoJavabeans?AperguntaquenãoquersecalarpodeserrespondidamuitofacilmenteumavezqueumadasmaioresconfusõesfeitasaíforaéentreJavabeanseEnterpriseJavaBeans(EJB).

Javabeanssãoclassesquepossuemoconstrutorsemargumentosemétodosdeacessodotipogete

set! Mais nada! Simples, não? Já os EJBs costumam ser javabeans com características mais

avançadas.

Podemos usar beans em diversas situações, como em classes que representam nosso modelo dedados.

Aseguir,vocêvêumexemplodeumaclasseJavaBeanqueseriaequivalenteaonossomodelodeentidadedobancodedados:

packagebr.com.caelum.jdbc.modelo;

publicclassContato{

privateLongid;privateStringnome;privateStringemail;privateStringendereco;privateCalendardataNascimento;

//métodosgetesetparaid,nome,email,endereçoedataNascimento

publicStringgetNome(){returnthis.nome;}publicvoidsetNome(Stringnovo){this.nome=novo;}

publicStringgetEmail(){returnthis.email;}

VocêpodetambémfazerocursodatadessaapostilanaCaelum

2.8JAVABEANS

2.8JAVABEANS 15

Page 25: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicvoidsetEmail(Stringnovo){this.email=novo;}

publicStringgetEndereco(){returnthis.endereco;}publicvoidsetEndereco(Stringnovo){this.endereco=novo;}

publicLonggetId(){returnthis.id;}publicvoidsetId(Longnovo){this.id=novo;}

publicCalendargetDataNascimento(){returnthis.dataNascimento;}publicvoidsetDataNascimento(CalendardataNascimento){this.dataNascimento=dataNascimento;}}

AespecificaçãoJavaBeansémuitograndeemaisinformaçõessobreessavastaáreaqueéabasedoscomponentesescritosemJavapodeserencontradaem:

http://docs.oracle.com/javase/tutorial/javabeans/

MÉTODOSGETTERSESETTERS

UmerromuitocomumcometidopelosdesenvolvedoresJavaéacriaçãodosmétodosgettersesettersindiscriminadamente,semterarealnecessidadedaexistênciadetaismétodos.

Existe um artigo no blog da Caelum que trata desse assunto:http://blog.caelum.com.br/2006/09/14/nao-aprender-oo-getters-e-setters/

Os cursosFJ-11 eFJ-22 tambémmostram isso claramente, quando criam algumas entidadesquenãopossuemapenasgettersesetters.

Para inserirdadosemumatabeladeumbancodedadosentidade-relacional,bastausaracláusulaINSERT.Precisamosespecificarquaisoscamposquedesejamosatualizareosvalores.

PrimeiroocódigoSQL:

Stringsql="insertintocontatos"+"(nome,email,endereco,dataNascimento)"+

2.9INSERINDODADOSNOBANCO

16 2.9INSERINDODADOSNOBANCO

Page 26: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

"values('"+nome+"','"+email+"','"+endereco+"','"+dataNascimento+"')";

O exemplo acima possui três pontos negativos que são importantíssimos. O primeiro é que oprogramadorquenãoescreveuocódigooriginalnãoconseguebateroolhoeentenderoqueestáescrito.O que o código acima faz? Lendo rapidamente fica difícil.Mais difícil ainda é saber se faltou umavírgula,umfechaparêntesestalvez?Eaindaassim,esseéumcasosimples.Existemtabelascom10,20,30 e até mais campos, tornando inviável entender o que está escrito no SQL misturado com asconcatenações.

Outro problema é o clássico "preconceito contra Joana D'arc", formalmente chamado de SQLInjection.Oque acontecequandoo contato a ser adicionadopossuinonomeumaaspas simples?OcódigoSQLsequebra todoeparade funcionarou,pior ainda,ousuário final é capazde alterar seucódigoSQLparaexecutaraquiloqueeledeseja(SQLinjection)...tudoissoporqueescolhemosaquelalinhadecódigoenãofizemosoescapedecaracteresespeciais.

Maisumproblemaqueenxergamosaíénadata.ElaprecisaserpassadacomoumaStringeno

formatoqueobancodedadosentenda,portanto,sevocêpossuiumobjetojava.util.Calendar,que

éonossocaso,vocêprecisaráfazeraconversãodesseobjetoparaaString.

Por esses trêsmotivosnãousaremos códigoSQLcomomostrado anteriormente.Vamos imaginaralgomaisgenéricoeumpoucomaisinteressante:

Stringsql="insertintocontatos"+"(nome,email,endereco,dataNascimento)"+"values(?,?,?,?)";

ExisteumamaneiraemJavadeescreverocódigoSQLcomonoprimeiroexemplodessaseção(comconcatenaçõesdeString).Essamaneiranãoseráensinadaduranteocursopoiséumapéssimaprática

quedificultaamanutençãodoseuprojeto.

Percebaquenãocolocamosospontosdeinterrogaçãodebrincadeira,massimporquerealmentenãosabemoso que desejamos inserir.Estamos interessados em executar aquele códigomas não sabemosainda quais são osparâmetros que utilizaremos nesse código SQL que será executado, chamado destatement.

AscláusulassãoexecutadasemumbancodedadosatravésdainterfacePreparedStatement.Para

receber umPreparedStatement relativo à conexão, basta chamar ométodo prepareStatement,

passandocomoargumentoocomandoSQLcomosvaloresvindosdevariáveispreenchidoscomumainterrogação.

Stringsql="insertintocontatos"+"(nome,email,endereco,dataNascimento)"+"values(?,?,?,?)";PreparedStatementstmt=connection.prepareStatement(sql);

2.9INSERINDODADOSNOBANCO 17

Page 27: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Logoemseguida, chamamosométodosetString doPreparedStatement para preencher os

valoresquesãodotipoString,passandoaposição (começandoem1)da interrogaçãonoSQLeo

valorquedevesercolocado:

//preencheosvaloresstmt.setString(1,"Caelum");stmt.setString(2,"[email protected]");stmt.setString(3,"R.Vergueiro3185cj57");

Precisamosdefinir tambémadatadenascimentodonossocontato,para isso,precisaremosdeumobjetodotipojava.sql.DateparapassarmosparaonossoPreparedStatement.Nesse exemplo,

vamospassaradataatual.Paraisso,vamospassarumlongquerepresentaosmilissegundosdadata

atual para dentrodeumjava.sql.Date, que é o tipo suportado pelaAPI JDBC.Vamos utilizar a

classeCalendarparaconseguirmosessesmilissegundos:

java.sql.DatedataParaGravar=newjava.sql.Date(Calendar.getInstance().getTimeInMillis());stmt.setDate(4,dataParaGravar);

Porfim,umachamadaaexecute()executaocomandoSQL:

stmt.execute();

Imagine todo esse processo sendo escrito toda vez que desejar inserir algo no banco?Ainda nãoconseguevisualizaroquãodestrutivoissopodeser?

Vejaoexemploabaixo,queabreumaconexãoeinsereumcontatonobanco:

publicclassJDBCInsere{

publicstaticvoidmain(String[]args)throwsSQLException{

//conectandoConnectioncon=newConnectionFactory().getConnection();

//criaumpreparedStatementStringsql="insertintocontatos"+"(nome,email,endereco,dataNascimento)"+"values(?,?,?,?)";PreparedStatementstmt=con.prepareStatement(sql);

//preencheosvaloresstmt.setString(1,"Caelum");stmt.setString(2,"[email protected]");stmt.setString(3,"R.Vergueiro3185cj57");stmt.setDate(4,newjava.sql.Date(Calendar.getInstance().getTimeInMillis()));

//executastmt.execute();stmt.close();

System.out.println("Gravado!");

con.close();}

18 2.9INSERINDODADOSNOBANCO

Page 28: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

NãoécomumutilizarJDBCdiretamentehojeemdia.OmaispraticadoéousodealgumaAPIdeORMcomoaJPAouoHibernate.TantonaJDBCquantoembibliotecasORMdeve-seprestaratençãonomomentodefecharaconexão.

Oexemplodadoacimanãoafechacasoalgumerroocorranomomentodeinserirumdadonobancodedados.Ocomuméfecharaconexãoemumblocofinally:

publicclassJDBCInsere{publicstaticvoidmain(String[]args)throwsSQLException{Connectioncon=null;try{con=newConnectionFactory().getConnection();

//fazummontedeoperações.//quepodemlançarexceptionsruntimeeSQLException}catch(SQLExceptione){System.out.println(e);}finally{con.close();}}}

Dessaforma,mesmoqueocódigodentrodotrylanceexception,ocon.close()seráexecutado.

Garantimosquenãodeixaremosumaconexãopenduradasemuso.Essecódigopodeficarmuitomaiorse quisermos ir além. Pois o que acontece no caso de con.close lançar uma exception? Quem a

tratará?

Trabalharcomrecursoscaros,comoconexões,sessões, threadsearquivos,sempredevesermuitobem pensado. Deve-se tomar cuidado para não deixar nenhum desses recursos abertos, pois poderávazaralgopreciosodanossaaplicação.Comoveremosduranteocurso, é importantecentralizaressetipodecódigoemalgumlugar,paranãorepetirumatarefacomplicadacomoessa.

Além disso, há a estrutura do Java 7 conhecida como try-with-resources. Ela permite declarar einicializar,dentrodotry,objetosque implementamAutoCloseable.Dessa forma, ao términodo

try, o próprio compilador inserirá instruções para invocar o close desses recursos, além de se

precaveremrelaçãoaexceçõesquepodemsurgirporcausadessainvocação.Nossocódigoficariamaisreduzidoeorganizado,alémdoescopodeconsóvalerdentrodotry:

try(Connectioncon=newConnectionFactory().getConnection()){//fazummontedeoperações.//quepodemlançarexceptionsruntimeeSQLException}catch(SQLExceptione){System.out.println(e);}

Parasabermais:Fechandoaconexãopropriamente

2.9INSERINDODADOSNOBANCO 19

Page 29: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Em vez de usar o PreparedStatement, você pode usar uma interface mais simples chamada

Statement,quesimplesmenteexecutaumacláusulaSQLnométodoexecute:

Statementstmt=con.createStatement();stmt.execute("INSERTINTO...");stmt.close();

MasprefiraaclassePreparedStatementqueémaisrápidaqueStatementedeixaseucódigo

muitomaislimpo.

Geralmente, seus comandos SQL conterão valores vindos de variáveis do programa Java; usandoStatements,vocêteráquefazermuitasconcatenações,masusandoPreparedStatements,issofica

maislimpoefácil.

AAPIdedatasdoJava,mesmoconsiderandoalgumasmelhoriasdaCalendaremrelaçãoaDate,

aindaémuitopobre.Naversão8doJavatemosumaAPInova,ajava.time,quefacilitabastanteo

trabalho.ElaébaseadanaexcelentebibliotecadedataschamadaJodaTime.

JáfoipossívelsentirquecolocarcódigoSQLdentrodesuasclassesdelógicaéalgonemumpoucoeleganteemuitomenosviávelquandovocêprecisamanteroseucódigo.

Quantasvezesvocênãoficoubravocomoprogramadorresponsávelporaquelecódigoilegível?

Aideiaaseguiréremoverocódigodeacessoaobancodedadosdesuasclassesdelógicaecolocá-loemumaclasseresponsávelpeloacessoaosdados.Assimocódigodeacessoaobancodedadosficaemumlugarsó,tornandomaisfácilamanutenção.

QuetalsepudéssemoschamarummétodoadicionaqueadicionaumContatoaobanco?

Emoutraspalavrasqueroqueocódigoaseguirfuncione:

//adicionaosdadosnobancoMisteriobd=newMisterio();bd.adiciona("meunome","meuemail","meuendereço",meuCalendar);

Tem algo estranho nesse código. Repare que todos os parâmetros que estamos passando são asinformaçõesdocontato.Secontatotivesse20atributos,passaríamos20parâmetros?JavaéorientadoaStrings?Vamostentarnovamente:emoutraspalavrasqueroqueocódigoaseguirfuncione:

//adicionaumcontatonobancoMisteriobd=newMisterio();

Parasabermais:AmápráticaStatement

Parasabermais:JodaTime

2.10DAO-DATAACCESSOBJECT

20 2.10DAO-DATAACCESSOBJECT

Page 30: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

//métodomuitomaiselegantebd.adiciona(contato);

Tentaremoschegaraocódigoanterior:seriamuitomelhoremaiselegantepoderchamarumúnicométodoresponsávelpelainclusão,certo?

publicclassTestaInsere{

publicstaticvoidmain(String[]args){

//prontoparagravarContatocontato=newContato();contato.setNome("Caelum");contato.setEmail("[email protected]");contato.setEndereco("R.Vergueiro3185cj87");contato.setDataNascimento(Calendar.getInstance());

//gravenessaconexão!!!Misteriobd=newMisterio();

//métodoelegantebd.adiciona(contato);

System.out.println("Gravado!");}}

Ocódigoanteriorjámostraopoderquealcançaremos:atravésdeumaúnicaclasseseremoscapazesdeacessarobancodedadose,maisainda,somenteatravésdessaclasseserápossívelacessarosdados.

Estaideia,inocenteàprimeiravista,écapazdeisolartodooacessoabancoemclassesbemsimples,cujainstânciaéumobjetoresponsávelporacessarosdados.DaresponsabilidadedesteobjetosurgiuonomedeDataAccessObjectousimplesmenteDAO,umdosmaisfamosospadrõesdeprojeto(designpattern).

Oque faltaparaocódigoacima funcionaréumaclassechamadaContatoDao comummétodo

chamadoadiciona.Vamoscriarumaqueseconectaaobancoaoconstruirmosumainstânciadela:

publicclassContatoDao{

//aconexãocomobancodedadosprivateConnectionconnection;

publicContatoDao(){this.connection=newConnectionFactory().getConnection();}}

Agora que todo ContatoDao possui uma conexão com o banco, podemos focar no método

adiciona, que recebe um Contato como argumento e é responsável por adicioná-lo através de

códigoSQL:

publicvoidadiciona(Contatocontato){Stringsql="insertintocontatos"+"(nome,email,endereco,dataNascimento)"+"values(?,?,?,?)";

2.10DAO-DATAACCESSOBJECT 21

Page 31: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

try{//preparedstatementparainserçãoPreparedStatementstmt=con.prepareStatement(sql);

//setaosvalores

stmt.setString(1,contato.getNome());stmt.setString(2,contato.getEmail());stmt.setString(3,contato.getEndereco());stmt.setDate(4,newDate(contato.getDataNascimento().getTimeInMillis()));

//executastmt.execute();stmt.close();}catch(SQLExceptione){thrownewRuntimeException(e);}}

Encapsulamos a SQLException em uma RuntimeException mantendo a ideia anterior da

ConnectionFactorydedesacoplarocódigodeAPIdeJDBC.

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

1. CrieaclassedeContatonopacotebr.com.caelum.jdbc.modelo.ElaseránossoJavaBeanpara

representaraentidadedobanco.Deveráterid,nome,email,endereçoeumadatadenascimento.

Coloqueosatributosnaclasseegereosgettersesettersparacadaatributo:

publicclassContato{privateLongid;privateStringnome;privateStringemail;privateStringendereco;privateCalendardataNascimento;

Seuslivrosdetecnologiaparecemdoséculopassado?

2.11EXERCÍCIOS:JAVABEANSECONTATODAO

22 2.11EXERCÍCIOS:JAVABEANSECONTATODAO

Page 32: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

Dica:useoatalhodoEclipseparagerarosgettersesetters.AperteCtrl+3,digiteggasqueéaabreviaçãodeGenerategettersandsetterseselecionetodososgettersesetters.

1. Vamos desenvolver nossa classe de DAO. Crie a classe ContatoDao no pacote

br.com.caelum.jdbc.dao. Seu papel será gerenciar a conexão e inserir Contatos no banco de

dados.

Paraaconexão,vamoscriá-lanoconstrutoresalvaremumatributo:

publicclassContatoDao{

//aconexãocomobancodedadosprivateConnectionconnection;

2.11EXERCÍCIOS:JAVABEANSECONTATODAO 23

Page 33: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicContatoDao(){this.connection=newConnectionFactory().getConnection();}

}

UseoEclipseparaajudarcomosimports!(atalhoCtrl+Shift+O)

O próximo passo é criar o método de adição de contatos. Ele deve receber um objeto do tipoContatocomoargumentoeencapsulartotalmenteotrabalhocomobancodedados.Internamente,use

umPreparedStatementcomovimosnaaulaparaexecutaroSQL:

publicvoidadiciona(Contatocontato){Stringsql="insertintocontatos"+"(nome,email,endereco,dataNascimento)"+"values(?,?,?,?)";

try{//preparedstatementparainserçãoPreparedStatementstmt=connection.prepareStatement(sql);

//setaosvaloresstmt.setString(1,contato.getNome());stmt.setString(2,contato.getEmail());stmt.setString(3,contato.getEndereco());stmt.setDate(4,newDate(contato.getDataNascimento().getTimeInMillis()));

//executastmt.execute();stmt.close();}catch(SQLExceptione){thrownewRuntimeException(e);}}

ATENÇÃO:Lembre-sedeimportarasclassesdeSQLdopacotejava.sql,inclusiveaclasseDate!

1. Antesdetestarainserçãodeumcontatonobancodedados,verifiqueseatabelacontatosexiste.

Abraoterminaledigite:

mysql-uroot

Lembrandoque,sehouversenhaparalogarcomobanco,éprecisoescrevermysql-uroot-pe,

emseguida,digitarasenhadobancodedados.

DentrodoMySQL,listetodasastabelasjácriadascomocomando:

showtables;

Procurepelatabelacontatos.Seelanãoexistir,criecomocomando:

createtablecontatos(idBIGINTNOTNULLAUTO_INCREMENT,

24 2.11EXERCÍCIOS:JAVABEANSECONTATODAO

Page 34: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

nomeVARCHAR(255),emailVARCHAR(255),enderecoVARCHAR(255),dataNascimentoDATE,primarykey(id));

(Dica:essecódigoencontra-senoarquivocontatos.sqlnapasta21/projeto-jdbc)

1. ParatestarnossoDAO,desenvolvaumaclassedetestescomométodomain.Porexemplo,uma

chamadaTestaInserenopacotebr.com.caelum.jdbc.teste.GereomainpeloEclipse.

Onossoprogramadetestesdeve,dentrodomain,criarumnovoobjetoContatocomdadosde

testeechamaranovaclasseContatoDaoparaadicioná-loaobancodedados:

//prontoparagravarContatocontato=newContato();contato.setNome("Caelum");contato.setEmail("[email protected]");contato.setEndereco("R.Vergueiro3185cj57");contato.setDataNascimento(Calendar.getInstance());

//gravenessaconexão!!!ContatoDaodao=newContatoDao();

//métodoelegantedao.adiciona(contato);

System.out.println("Gravado!");

Executeseuprogramaevejasetudocorreubem.

1. Verifiqueseocontatofoiadicionado.Abraoterminaledigite:

mysql-urootusefj21;select*fromcontatos;

Lembrandoquesehouversenhaparaousuárioroot,oprimeirocomandodeveser:mysql-u

root-p.DigiteexitparasairdoconsoledoMySQL.

Para pesquisar tambémutilizamos a interfacePreparedStatement paramontar nosso comando

SQL. Mas como uma pesquisa possui um retorno (diferente de uma simples inserção), usaremos ométodoexecuteQueryqueretornatodososregistrosdeumadeterminadaquery.

OobjetoretornadoédotipoResultSetdoJDBC,oquenospermitenavegarporseusregistros

atravésdométodonext.Essemétodoretornaráfalsequandochegaraofimdapesquisa,portanto

eleénormalmenteutilizadoparafazerumlaçonosregistros:

//pegaaconexãoeoStatement

2.12FAZENDOPESQUISASNOBANCODEDADOS

2.12FAZENDOPESQUISASNOBANCODEDADOS 25

Page 35: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Connectioncon=newConnectionFactory().getConnection();PreparedStatementstmt=con.prepareStatement("select*fromcontatos");

//executaumselectResultSetrs=stmt.executeQuery();

//iteranoResultSetwhile(rs.next()){}

rs.close();stmt.close();con.close();

Para retornarovalordeumacolunanobancodedados,basta chamarumdosmétodosget do

ResultSet,dentreosquais,omaiscomum:getString.

//pegaaconexãoeoStatementConnectioncon=newConnectionFactory().getConnection();PreparedStatementstmt=con.prepareStatement("select*fromcontatos");

//executaumselectResultSetrs=stmt.executeQuery();

//iteranoResultSetwhile(rs.next()){Stringnome=rs.getString("nome");Stringemail=rs.getString("email")

System.out.println(nome+"_"+email);}

stmt.close();con.close();

RECURSOAVANÇADO:OCURSOR

Assimcomoocursordobancodedados, só épossívelmoverparaopróximo registro.ParapermitirumprocessodeleituraparatrásénecessárioespecificarnaaberturadoResultSetque

talcursordeveserutilizado.

Mas, novamente, podemos aplicar as ideias deDAO e criar ummétodogetLista() no nossoContatoDao . Mas o que esse método retornaria? Um ResultSet ? E teríamos o código de

manipulaçãodeResultSetespalhadoportodoocódigo?VamosfazernossogetLista() devolver

algomaisinteressante,umalistadeContato:

PreparedStatementstmt=this.connection.prepareStatement("select*fromcontatos");ResultSetrs=stmt.executeQuery();

List<Contato>contatos=newArrayList<Contato>();

26 2.12FAZENDOPESQUISASNOBANCODEDADOS

Page 36: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

while(rs.next()){

//criandooobjetoContatoContatocontato=newContato();contato.setNome(rs.getString("nome"));contato.setEmail(rs.getString("email"));contato.setEndereco(rs.getString("endereco"));

//montandoadataatravésdoCalendarCalendardata=Calendar.getInstance();data.setTime(rs.getDate("dataNascimento"));contato.setDataNascimento(data);

//adicionandooobjetoàlistacontatos.add(contato);}

rs.close();stmt.close();

returncontatos;

1. CrieométodogetListanaclasseContatoDao.ImporteListdejava.util:

publicList<Contato>getLista(){try{List<Contato>contatos=newArrayList<Contato>();PreparedStatementstmt=this.connection.prepareStatement("select*fromcontatos");ResultSetrs=stmt.executeQuery();

while(rs.next()){//criandooobjetoContatoContatocontato=newContato();contato.setId(rs.getLong("id"));contato.setNome(rs.getString("nome"));contato.setEmail(rs.getString("email"));contato.setEndereco(rs.getString("endereco"));

//montandoadataatravésdoCalendarCalendardata=Calendar.getInstance();data.setTime(rs.getDate("dataNascimento"));contato.setDataNascimento(data);

//adicionandooobjetoàlistacontatos.add(contato);}rs.close();stmt.close();returncontatos;}catch(SQLExceptione){thrownewRuntimeException(e);}}

1. VamosusarométodogetListaparalistartodososcontatosdonossobancodedados.

2.13EXERCÍCIOS:LISTAGEM

2.13EXERCÍCIOS:LISTAGEM 27

Page 37: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CrieumaclassechamadaTestaListacomummétodomain:

CrieumContatoDao:

ContatoDaodao=newContatoDao();

ListeoscontatoscomoDAO:

List<Contato>contatos=dao.getLista();

Iterenessalistaeimprimaasinformaçõesdoscontatos:

for(Contatocontato:contatos){System.out.println("Nome:"+contato.getNome());System.out.println("Email:"+contato.getEmail());System.out.println("Endereço:"+contato.getEndereco());System.out.println("DatadeNascimento:"+contato.getDataNascimento().getTime()+"\n");}

1. RodeoprogramaacimaclicandoemRun>Runas>JavaApplication(aproveiteparaaprenderatecladeatalhoparaexecutaraaplicação).

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

AssimcomooMySQLexistemoutrosbancosdedadosgratuitoseopensourcenainternet.OH2éumbancodesenvolvidoemJavaquepodeseracopladoaqualqueraplicaçãoeliberaoclientedanecessidadedebaixarqualquerbancodedadosantesdainstalaçãodeumprodutoJava!

OHibernate tomoucontadomercadoevirou febremundial poisnão se faznecessário escreverumalinhadecódigoSQL!

SeumprojetonãousanenhumadastecnologiasdeORM(ObjectRelationalMapping)disponíveis,omínimoaserfeitoéseguiroDAO.

Agoraéamelhorhoradeaprenderalgonovo

2.14UMPOUCOMAIS...

28 2.14UMPOUCOMAIS...

Page 38: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. A impressão da data de nascimento ficou um pouco estranha. Para formatá-la, pesquise sobre aclasseSimpleDateFormat.

2. Crie uma classe chamadaDAOException que estenda deRuntimeException e utilize-a no seu

ContatoDao.

3. Usecláusulaswherepararefinarsuapesquisanobancodedados.Porexemplo:wherenomelike

'C%'

4. Crieométodopesquisarquerecebeumid(int)eretornaumobjetodotipoContato.

1. Façaconexõesparaoutrostiposdebancodedadosdisponíveis.

AgoraquevocêjásabeusaroPreparedStatementparaexecutarqualquertipodecódigoSQLe

ResultSetparareceberosdadosretornadosdasuapesquisaficasimples,porémmaçante,escrevero

códigodediferentesmétodosdeumaclassetípicadeDAO.

Vejaprimeiroométodoaltera,querecebeumcontatocujosvaloresdevemseralterados:

publicvoidaltera(Contatocontato){Stringsql="updatecontatossetnome=?,email=?,endereco=?,"+"dataNascimento=?whereid=?";try{PreparedStatementstmt=connection.prepareStatement(sql);stmt.setString(1,contato.getNome());stmt.setString(2,contato.getEmail());stmt.setString(3,contato.getEndereco());stmt.setDate(4,newDate(contato.getDataNascimento().getTimeInMillis()));stmt.setLong(5,contato.getId());stmt.execute();stmt.close();}catch(SQLExceptione){thrownewRuntimeException(e);}}

Nãoexistenadadenovonaslinhasacima.Umaexecuçãodequery!Simples,não?

Ocódigopararemoção:começacomumaquerybaseadaemumcontato,masusasomenteoiddeleparaexecutaraquerydotipodelete:

publicvoidremove(Contatocontato){try{PreparedStatementstmt=connection.prepareStatement("delete"+"fromcontatoswhereid=?");stmt.setLong(1,contato.getId());

2.15EXERCÍCIOSOPCIONAIS

Desafios

2.16OUTROSMÉTODOSPARAOSEUDAO

2.15EXERCÍCIOSOPCIONAIS 29

Page 39: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

stmt.execute();stmt.close();}catch(SQLExceptione){thrownewRuntimeException(e);}}

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

1. AdicioneométodoparaalterarcontatonoseuContatoDao.

publicvoidaltera(Contatocontato){Stringsql="updatecontatossetnome=?,email=?,"+"endereco=?,dataNascimento=?whereid=?";

try{PreparedStatementstmt=connection.prepareStatement(sql);stmt.setString(1,contato.getNome());stmt.setString(2,contato.getEmail());stmt.setString(3,contato.getEndereco());stmt.setDate(4,newDate(contato.getDataNascimento().getTimeInMillis()));stmt.setLong(5,contato.getId());stmt.execute();stmt.close();}catch(SQLExceptione){thrownewRuntimeException(e);}}

1. AdicioneométodopararemovercontatonoseuContatoDao

publicvoidremove(Contatocontato){try{PreparedStatementstmt=connection.prepareStatement("deletefromcontatoswhereid=?");stmt.setLong(1,contato.getId());stmt.execute();

EditoraCasadoCódigocomlivrosdeumaformadiferente

2.17EXERCÍCIOSOPCIONAIS-ALTERAREREMOVER

30 2.17EXERCÍCIOSOPCIONAIS-ALTERAREREMOVER

Page 40: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

stmt.close();}catch(SQLExceptione){thrownewRuntimeException(e);}}

1. Useosmétodoscriadosanteriormenteparafazertestescomoseubancodedados:atualizeeremovaumcontato.

2. CrieumaclassechamadaFuncionariocomoscamposid(Long),nome,usuarioesenha(String).3. Crieumatabelanobancodedadoschamadafuncionarios.4. CrieumaclasseDAOparaFuncionario.5. Use-aparainstanciarnovosfuncionáriosecolocá-losnoseubanco.

2.17EXERCÍCIOSOPCIONAIS-ALTERAREREMOVER 31

Page 41: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO3

"Ensinaréaprenderduasvezes."--JosephJoubert

Aotérminodessecapítulo,vocêserácapazde:

EntenderoqueéoJavaEnterpriseEdition;DiferenciarumServidordeAplicaçãodeumServletContainer;InstalarumServletContainercomooApacheTomcat;ConfigurarumServletContainerdentrodoEclipse.

As aplicaçõesWebdehoje emdia jápossuem regrasdenegóciobastante complicadas.Codificaressasmuitasregrasjárepresentamumgrandetrabalho.Alémdessasregras,conhecidascomorequisitosfuncionais de uma aplicação, existem outros requisitos que precisam ser atingidos através da nossainfraestrutura:persistênciaembancodedados,transação,acessoremoto,webservices,gerenciamentode threads, gerenciamento de conexões HTTP, cache de objetos, gerenciamento da sessão web,balanceamentodecarga,entreoutros.Sãochamadosderequisitosnão-funcionais.

Seformostambémosresponsáveisporescrevercódigoquetratedessesoutrosrequisitos,teríamosmuitomaistrabalhoafazer.Tendoissoemvista,aSuncriouumasériedeespecificaçõesque,quandoimplementadas, podem ser usadas por desenvolvedores para tirar proveito e reutilizar toda essainfraestruturajápronta.

OJavaEE(JavaEnterpriseEdition)consistedeumasériedeespecificaçõesbemdetalhadas,dandouma receita de como deve ser implementado um software que faz cada um desses serviços deinfraestrutura.

Veremosnodecorrerdessecursováriosdessesserviçosecomoutilizá-los,focandonoambientededesenvolvimentowebatravésdoJavaEE.Veremos tambémconceitosmuito importantes,paradepoisconceituartermosfundamentaiscomoservidordeaplicaçãoecontainers.

PorqueaSunfazisso?Aideiaéquevocêpossacriarumaaplicaçãoqueutilizeessesserviços.Comoesses serviços são bem complicados, você não perderá tempo implementando essa parte do sistema.Existemimplementaçõestantoopensourcequantopagas,ambasdeboaqualidade.

OQUEÉJAVAEE?

3.1COMOOJAVAEEPODETEAJUDARAENFRENTARPROBLEMAS

32 3OQUEÉJAVAEE?

Page 42: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Algum dia, você pode querer trocar essa implementação atual por uma que é mais rápida emdeterminadospontos,queusemenosmemória,etc.Fazendoessamudançadeimplementaçãovocênãoprecisará alterar seu software, já que o JavaEE é uma especificaçãomuito bemdeterminada.O quemuda é a implementação da especificação: você tem essa liberdade, não está preso a um código e aespecificaçãogarantequesuaaplicaçãofuncionarácomaimplementaçãodeoutrofabricante.Esseéumatrativomuitograndeparagrandesempresasegovernos,quequeremsempreevitarovendor lock-in:expressãousadaquandovocêestápresosemprenasmãosdeumúnicofabricante.

ONDEENCONTRARASESPECIFICAÇÕES

O grupo responsável por gerir as especificações usa o site do Java Community Process:http://www.jcp.org/

Lá você pode encontrar tudo sobre as Java SpecificationRequests (JSR), isto é, os novospedidosdebibliotecaseespecificaçõesparaoJava,tantoparaJavaSE,quantoEEeoutros.

SobreoJavaEE,vocêpodeencontrarem:http://java.sun.com/javaee/

J2EE

OnomeJ2EEerausadonasversõesmaisantigas,atéa1.4.Hoje,onomecorretoéJavaEE,porumaquestãodemarketing,masvocêaindavaiencontrarmuitas referênciasaoantigo termoJ2EE.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Agoraéamelhorhoradeaprenderalgonovo

3.1COMOOJAVAEEPODETEAJUDARAENFRENTARPROBLEMAS 33

Page 43: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

AsAPIsaseguirsãoasprincipaisdentreasdisponibilizadaspeloJavaEnterprise:

JavaServer Pages (JSP), Java Servlets, Java Server Faces (JSF) (trabalhar para a Web, onde éfocadoestecurso)

Enterprise Javabeans Components (EJB) e Java Persistence API (JPA). (objetos distribuídos,clusters,acessoremotoaobjetosetc)

JavaAPIforXMLWebServices(JAX-WS),JavaAPIforXMLBinding(JAX-B)(trabalharcomarquivosxmlewebservices)

JavaAutenthicationandAuthorizationService(JAAS)(APIpadrãodoJavaparasegurança)

JavaTransactionAPI(JTA)(controledetransaçãonocontêiner)

JavaMessageService(JMS)(trocademensagensassíncronas)

JavaNamingandDirectoryInterface(JNDI)(espaçodenomeseobjetos)

JavaManagementExtensions(JMX)(administraçãodasuaaplicaçãoeestatísticassobreamesma)

AúltimaversãodisponíveldaespecificaçãodoJavaEEéaversão7, lançadaem12de junhode2013.Éumaversão aindamuito recente, compoucas ferramentas e servidores disponíveis.Aversãomaisusadanomercadoéaversão6,de2009.Estecursoéfocadonaversão6quevocêencontraránomercadoe jáapresentandoasnovidadesdonovoJavaEE7quedeveganharespaçonomercadonospróximosanos.

Neste curso FJ-21, atacamos especialmente JSP e Servlets. No curso FJ-26, estuda-se comprofundidadeJSFcomCDIeJBossSeam.NoFJ-25éapresentadoemdetalheJPAcomHibernateeoEJB. No FJ-36, estuda-se as especificações mais relacionadas a sistemas de alto desempenho: EJB,JNDI,JMS,JAX-BalémdeWebServices(JAX-WSeJAX-RS).

JSPeServletssãosemdúvidaasespecificaçõesessenciaisquetododesenvolvedorJavavaiprecisarparadesenvolvercomaWeb.MesmousandoframeworksebibliotecasquefacilitamotrabalhoparaaWeb, conhecer bem essas especificações é certamente um diferencial, e fará com que você entendamotivaçõesedificuldades,auxiliandonatomadadedecisõesarquiteturaisededesign.

Como vimos, o Java EE é um grande conjunto de especificações. Essas especificações, quandoimplementadas,vãoauxiliarbastanteodesenvolvimentoda suaaplicação,poisvocênãoprecisará sepreocuparcomgrandepartedecódigodeinfraestrutura,quedemandariamuitotrabalho.

3.2ALGUMASESPECIFICAÇÕESDOJAVAEE

3.3SERVIDORDEAPLICAÇÃO

34 3.2ALGUMASESPECIFICAÇÕESDOJAVAEE

Page 44: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Comofazero"downloaddoJavaEE"?O JavaEEé apenasumgrandePDF, uma especificação,detalhando quais especificações fazem parte deste. Para usarmos o software, é necessário fazer odownloaddeumaimplementaçãodessasespecificações.

Existemdiversas dessas implementações. Já que esse software tempapel de servir sua aplicaçãoparaauxiliá-lacomserviçosdeinfraestrutura,essesoftwareganhaonomedeservidordeaplicação.AprópriaSun/Oracledesenvolveumadessasimplementações,oGlassfishqueéopensourceegratuito,porémnãoéolíderdemercadoapesardeganharforçanosúltimostempos.

Existem diversos servidores de aplicação famosos compatíveis com a especificação do J2EE 1.4,JavaEE5ealguns jádoJavaEE6.OJBosséumdos líderesdomercadoe temavantagemdesergratuitoeopensource.AlgunssoftwaresimplementamapenasumapartedessasespecificaçõesdoJavaEE, comooApacheTomcat, que só implementa JSP eServlets (comodissemos, duas das principaisespecificações),portantonãoé totalmentecorretochamá-lodeservidordeaplicação.ApartirdoJavaEE6, existeo termo"applicationserverwebprofile",parapoder se referenciar a servidoresquenãooferecemtudo,masumgrupomenordeespecificações,consideradasessenciaisparaodesenvolvimentoweb.

Você pode ver uma lista de servidores Java EE 5 aqui:http://java.sun.com/javaee/overview/compatibility-javaee5.jsp

E Java EE 6 aqui, onde a lista ainda está crescendo:http://java.sun.com/javaee/overview/compatibility.jsp

Algunsdosservidoresdeaplicaçãomaisconhecidosdomercado:

Oracle/Sun,GlassFishServerOpenSourceEdition4.0,gratuito,JavaEE7;RedHat,JBossApplicationServer7.x,gratuito,JavaEE6;Apache,ApacheGeronimo,gratuito,JavaEE6(nãocertificado);Oracle/BEA,OracleWebLogicServer8.x,JavaEE6;IBM,IBMWebSphereApplicationServer,JavaEE6;SAP,SAPNetWeaverApplicationServerouSAPWebApplicationServer,JavaEE6WebProfile;

Nos cursos da Caelum utilizamos o Apache Tomcat e o RedHat JBoss, mas todo conhecimentoadquiridoaquipodeseraplicadocomfacilidadeparaosoutrosservidorescompatíveis,mudandoapenasaformadeconfigurá-los.

NocursoFJ-36,estuda-seprofundamentealgumasdasoutrastecnologiasenvolvidasnoJavaEE:oEJB,oJMS,oJAX-WSparaWebServiceseoJNDI.

O Java EE possui várias especificações, entre elas, algumas específicas para lidar com o

3.4SERVLETCONTAINER

3.4SERVLETCONTAINER 35

Page 45: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

desenvolvimentodeumaaplicaçãoWeb:

ServletJSPJSTLJSF

UmServletContaineréumservidorquesuportaessasfuncionalidades,masnãonecessariamenteoJavaEEWebProfilenemoJavaEEcompleto.ÉindicadoaquemnãoprecisadetudodoJavaEEeestáinteressadoapenasnaparteweb(boapartedasaplicaçõesdemédioporteencaixam-senessacategoria).

Háalgunsservletcontainersfamososnomercado.OmaisfamosoéoApacheTomcat,masháoutroscomooJetty,quenósdaCaelumusamosmuitoemprojetoseoGoogleusaemseucloudGoogleAppEngine.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

ParaprepararoTomcatnaCaelum,sigaosseguintespassos:

1. Entrenapasta21/projeto-agenda/tomcat-9doDesktopeselecioneoarquivodoapache-tomcat-9.x;

2. DêdoiscliquesparaabriroArchiveManagerdoLinux;

EditoraCasadoCódigocomlivrosdeumaformadiferente

3.5EXERCÍCIOS:PREPARANDOOTOMCAT

36 3.5EXERCÍCIOS:PREPARANDOOTOMCAT

Page 46: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

3. CliqueemExtract;4. EscolhaoseuDesktopecliqueemextract;

5. Oresultadoéumapastachamadaapache-tomcat-9.x.Pronto,otomcatjáestáinstalado.

Baixe o Tomcat 9 em http://tomcat.apache.org/ na página de downloads da versão que

escolher,vocêprecisarádeuma"BinaryDistribution".Mesmonowindows,dêpreferênciaaversão.zip,paravocê entendermelhoroprocessode inicializaçãodo servidor.Aversão executável é apenasumwrapperparaexecutaraJVM,jáqueoTomcaté100%Java.

OTomcatfoipormuitotempoconsideradoaimplementaçãopadrãoereferênciadasnovasversões

3.6PREPARANDOOTOMCATEMCASA

3.6PREPARANDOOTOMCATEMCASA 37

Page 47: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

da API de servlets. Ele também é o servlet container padrão utilizado pelo JBoss. Ele continua emprimeiraposiçãonomercado,mashojetemesselugardisputadopeloJettyepeloGrizzly(esseúltimoéoservletcontainerquefazpartedoservidordeaplicaçãodaOracle/Sun,oGlassfish).

Entrenodiretóriodeinstalação,depermissãodeexecuçãoatodososscriptsdessapastaeporfimexecuteostartup.shparaoservidorinicializar:

cdapache-tomcat<TAB>/binsudochmod+x*startup*.sh./startup.sh

UsingCATALINA_BASE:/home/fsouto/ÁreadeTrabalho/apache-tomcat-9.0.34UsingCATALINA_HOME:/home/fsouto/ÁreadeTrabalho/apache-tomcat-9.0.34...Tomcatstarted.

Parapararoservidorutilizeoscriptshutdown.sh:

cdapache-tomcat<TAB>/bin./shutdown.sh

AprenderemosfuturamentecomoiniciarocontainerdedentrodopróprioEclipse,porcomodidadeeparafacilitarousododebug.

ParainstalaroTomcatnoWindowsbastaexecutaroarquivo.exequepodeserbaixadonositedo

Tomcat(comofalamos,dêpreferênciaaozip).Depoisdisso,vocêpodeusarosscriptsstartup.bate

shutdown.bat,analogamenteaosscriptsdoLinux.

TudooquevamosdesenvolvernestecursofuncionaemqualquerambientecompatívelcomoJavaEnterpriseEdition,sejaoLinux,WindowsouMacOS.

OJettyéumaoutraimplementaçãocriadapelaMortBay(https://www.eclipse.org/jetty/)deServletContainereHTTPServer.Em2009passouaserhospedadonafundaçãoEclipse.

Pequeno e eficiente, ele é uma opção ao Tomcat bastante utilizada devido a algumas de suascaracterísticas.Especialmente:

facilmenteembarcável;escalável;"plugabilidade":éfáciltrocarasimplementaçõesdosprincipaiscomponentesdaAPI.

OJettytambémcostumaimplementar,antesdoTomcat,ideiasdiferentesqueaindanãoestãonaAPIdeservletsdoJavaEE.UmadessasimplementaçõespioneirasfoidousodoschamadosconectoresNIO,

TomcatnoWindows

3.7OUTRAOPÇÃO:JETTY

38 3.7OUTRAOPÇÃO:JETTY

Page 48: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

porexemplo,quepermitiramumaperformancemelhorparaousodeAJAX.

O GUJ.com.br roda com o Jetty, em uma instalação customizada que pode ser lida aqui:https://blog.caelum.com.br/melhorando-o-guj-jetty-nio-e-load-balancing/amp/

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

Sempre que estamos trabalhando como desenvolvimento de uma aplicação queremos ser omaisprodutivos possível, e não é diferente com uma aplicação web. Uma das formas de aumentar aprodutividade do desenvolvedor é utilizar uma ferramenta que auxilie no desenvolvimento e o tornemaiságil,nonossocaso,umaIDE.

O WTP, Web Tools Platform, é um conjunto de plugins para o Eclipse que auxilia odesenvolvimentodeaplicaçõesJavaEE,emparticular,deaplicaçõesWeb.ContémdesdeeditoresparaJSP,CSS,JSeHTMLatéperspectivasejeitosderodarservidoresdedentrodoEclipse.

Estepluginvainosajudarbastantecomcontent-assistseatalhosparatornarodesenvolvimentoWebmaiseficiente.

AversãodedownloadEclipseIDEforJavaEEDevelopersjávemporpadrãocomoplugin.Sendoassim,bastairnositedoEclipsee:

Abraapáginawww.eclipse.org/downloads;

BaixeoEclipseIDEforJavaEEDevelopers;Descompacteoarquivoepronto.

JáconheceoscursosonlineAlura?

3.8INTEGRANDOOTOMCATNOECLIPSE

3.9OPLUGINWTP

3.8INTEGRANDOOTOMCATNOECLIPSE 39

Page 49: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

VamosprimeiroconfigurarnoWTPoservidorTomcatqueacabamosdedescompactar.

1. Mude a perspectiva doEclipse paraJava (e não Java EE, por enquanto). Para isso, vá no cantodireitosuperiorecliquenobotão:

DepoisselecioneJava:

2. AbraaViewdeServersnaperspectivaatual.AperteCtrl+3edigiteServers:

3. CliquecomobotãodireitodentrodaabaServerseváemNew>Server:

3.10EXERCÍCIOS:CONFIGURANDOOTOMCATNOECLIPSE

40 3.10EXERCÍCIOS:CONFIGURANDOOTOMCATNOECLIPSE

Page 50: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

4. SelecioneoApacheTomcat9.0ecliqueemNext:

5. Napróximatela,selecioneodiretórioondevocêdescompactouoTomcatecliqueemFinish:

3.10EXERCÍCIOS:CONFIGURANDOOTOMCATNOECLIPSE 41

Page 51: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

6. Porpadrão,oWTPgerenciatodooTomcatparanósenãopermitequeconfiguraçõessejamfeitasporforadoEclipse.Parasimplificar,vamosdesabilitarissoedeixaroTomcatnomodopadrãodopróprioTomcat.NaabaServers,dêdoiscliquesnoservidorTomcatqueumateladeconfiguraçãoseabrirá. Localize a seção Server Locations. Repare que a opção use workspace metadata estámarcada.MarqueaopçãoUseTomcatinstallation:Percebaqueapareceuumasterisconaaba,salveefecheessatela.

42 3.10EXERCÍCIOS:CONFIGURANDOOTOMCATNOECLIPSE

Page 52: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

7. Selecione o servidor que acabamos de adicionar e clique em Start (ícone play verde na viewservers):

8. Abra o navegador e acesse a URL http://localhost:8080/ Deve aparecer uma tela de

mensagemdoTomcat.Pronto!OWTPestáconfiguradopararodarcomoTomcat!

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

VocêpodetambémfazerocursodatadessaapostilanaCaelum

3.10EXERCÍCIOS:CONFIGURANDOOTOMCATNOECLIPSE 43

Page 53: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO4

"Sãomuitososqueusamarégua,maspoucososinspirados."--Platão

Aotérminodessecapítulo,vocêserácapazde:

criarumnovoprojetoWebnoEclipse;compreenderquaissãoosdiretóriosimportantesdeumaaplicaçãoWeb;compreenderquaissãoosarquivosimportantesdeumaaplicaçãoWeb;entenderondecolocarsuaspáginasearquivosestáticos.

Nesse capítulo veremos como, passo a passo, criar um novo projetoWeb no Eclipse usando osrecursosdoEclipseJavaEE.Dessaformanãoprecisarmosiniciaroservletcontainernamão,alémdepermitiraconfiguraçãodeumprojeto,desuasbibliotecas,edeseudebug,deumamaneirabemmaissimplesdoquesemele

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

1. VáemNew>ProjecteselecioneDynamicWebProjectecliqueNext:

NOVOPROJETOWEBUSANDOECLIPSE

4.1NOVOPROJETO

Seuslivrosdetecnologiaparecemdoséculopassado?

4.2EXERCÍCIOS:NOVOPROJETOWEB

44 4NOVOPROJETOWEBUSANDOECLIPSE

Page 54: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

2. Coloqueonomedoprojetocomofj21-agenda,verifiqueseoTargetruntimeestáapontandoparaaversãodoTomcatqueacabamosdeconfigurareseoDynamicwebmoduleversionestáconfiguradopara4.0.DepoiscliqueNext.ATENÇÃO:NÃOCLIQUEEMFinishAINDA!!!

4.2EXERCÍCIOS:NOVOPROJETOWEB 45

Page 55: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

3. CliqueemNextnaconfiguraçãodaspastas:

46 4.2EXERCÍCIOS:NOVOPROJETOWEB

Page 56: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

4. NaconfiguraçãoWebmodulemarqueoboxGenerateweb.xmldeploymentdescriptorecliqueemFinish:

5. SeforperguntadosobreamudançaparaaperspectivaJavaEE,selecioneNão.

4.2EXERCÍCIOS:NOVOPROJETOWEB 47

Page 57: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

6. O último passo é configurar o projeto para rodar noTomcat que configuramos.Na abaServers,cliquecomobotãodireitonoTomcateváemAddandRemove...:

7. Bastaselecionaronossoprojetofj21-agendaeclicaremAdd:

8. Dêumaolhadanaspastasqueforamcriadasenaestruturadonossoprojetonesseinstante.Vamosanalisá-laemdetalhes.

4.3ANÁLISEDORESULTADOFINAL

48 4.3ANÁLISEDORESULTADOFINAL

Page 58: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Olhebemaestruturadepastaseveráalgoparecidocomoquesegue:

Odiretóriosrc já é velho conhecido. É onde vamos colocar nosso código fonte Java. Em um

projetonormaldoEclipse,essasclassesseriamcompiladasparaapastabin,masnoEclipseécostume

seusarapastabuildquevemosemnossoprojeto.

Nosso projeto será composto demuitas páginasWeb e vamos querer acessá-lo no navegador. Jásabemosqueoservidoréacessadopelohttp://localhost:8080,mascomoseráquedizemosque

queremosacessaronossoprojetoenãooutrosprojetos?

No Java EE, trabalhamos com o conceito de contextosWeb para diferenciar sites ou projetosdistintosemummesmoservidor.Naprática,écomoumapastavirtualque,quandoacessada,remeteaalgumprojetoemquestão.

Porpadrão,oEclipsegeraocontextname comomesmonomedoprojeto;nonossocaso, fj21-agenda.PodemosmudarissonahoradecriaroprojetoouposteriormenteindoemProject>Properties>WebProjectSettingsemudandoaopçãoContextRoot.Reparequenãoénecessárioqueonomedocontextosejaomesmonomedoprojeto.

Assim,paraacessaroprojeto,usaremosaURL:http://localhost:8080/fj21-agenda/

MasoqueseráquevaiaparecerquandoabrirmosessaURL?Seráqueveremostodooconteúdodoprojeto?Porexemplo,serápossívelacessarapastasrcqueestádentrodonossoprojeto?Tomaraquenão,afinaltodonossocódigofonteestálá.

Para solucionar isso, uma outra configuração é importante no Eclipse: oContentDirectory. Aoinvésdeabriracessoatudo,criamosumapastadentrodoprojetoedizemosqueelaéaraiz(root)doconteúdo a ser exibido no navegador. No Eclipse, por padrão, é criada a pastaWebContent, mas

4.3ANÁLISEDORESULTADOFINAL 49

Page 59: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

poderia ser qualquer outra pasta configurada na criação do projeto (outro nome comumde se usar éweb).

Tudoque colocarmosnapastaWebContent será acessível naURLdo projeto. Por exemplo, se

queremosumapáginadeboasvindas:

http://localhost:8080/fj21-agenda/bemvindo.html

entãocriamosoarquivo:

fj21-agenda/WebContent/bemvindo.html

Repare também que dentro da WebContent há uma pasta chamada WEB-INF . Essa pasta é

extremamente importante para qualquer projeto web Java EE. Ela contém configurações e recursosnecessáriosparanossoprojetorodarnoservidor.

Oweb.xmléoarquivoondeficaráarmazenadaasconfiguraçõesrelativasasuaaplicação,usaremosessearquivoembreve.

Porenquanto,abra-oevejasuaestrutura,atéentãobemsimples:

<?xmlversion="1.0"encoding="UTF-8"?><web-appxmlns: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/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"id="WebApp_ID"version="2.5">

<display-name>fj21-agenda</display-name>

<welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list></web-app>

ÉobásicogeradopelopróprioEclipse.Tudooqueelefazédefinironomedaaplicaçãoealistadearquivosacessadosquevãoserprocuradosporpadrão.Todasessasconfiguraçõessãoopcionais.

Repare ainda que há uma pasta chamada lib dentro daWEB-INF. Quase todos os projetosWebexistentes precisamusar bibliotecas externas, comopor exemplo o driver doMySQLno nosso caso.Copiaremostodaselasparaessapastalib.Comoessediretóriosóaceitabibliotecas,apenascolocamosnele arquivos .jar ou arquivos zip com classes dentro. Caso um arquivo com outra extensão sejacolocadonolib,eleseráignorado.

WEB-INF

50 4.3ANÁLISEDORESULTADOFINAL

Page 60: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

WEB-INF/LIB

O diretório lib dentro do WEB-INF pode conter todas as bibliotecas necessárias para aaplicação Web, evitando assim que o classpath da máquina que roda a aplicação precise seralterado.

Além do mais, cada aplicaçãoWeb poderá usar suas próprias bibliotecas com suas versõesespecíficas!Vocêvaiencontrarprojetosopensourcequesomentefornecemsuporteerespondemperguntas aqueles usuários que utilizam tal diretório para suas bibliotecas, portanto evite aomáximoousodoclasspathglobal.

Parasabermaissobreousodeclassloaderseclasspathglobal,vocêpodeprocurarnocapítulo2dolivroIntroduçãoàArquiteturaeDesigndeSoftware,publicadopelaEditoraCasadoCódigoepelaElsevier.

Há ainda umúltimo diretório, oculto noEclipse, o importanteWEB-INF/classes. Para rodarmosnossa aplicação no servidor, precisamos ter acesso as classes compiladas (não necessariamente aocódigo fonte).Por isso, nossos.class são colocados nessa pasta dentro do projeto.Esse padrão é

definido pela especificação de Servlets do JavaEE.Repare que oEclipse compila nossas classes napastabuildedepoisautomaticamenteascopiaparaoWEB-INF/classes.

NotequeapastaWEB-INFémuitoimportanteecontémrecursosvitaisparaofuncionamentodoprojeto. Imagine se o usuário tiver acesso a essa pasta! Códigos compilados (facilmentedescompiláveis), bibliotecas potencialmente sigilosas, arquivos de configuração internos contendosenhas,etc.

Paraque issonãoaconteça,apastaWEB-INF comessenomeespecial éumapasta invisível aousuário final. Isso quer dizer que se alguém acessar a URL http://localhost:8080/fj21-agenda/WEB-INFveráapenasumapáginadeerro(404).

src-códigofonteJava(.java)build-ondeoEclipsecompilaasclasses(.class)WebContent-contentdirectory(páginas,imagens,cssetcvãoaqui)WebContent/WEB-INF/-pastaocultacomconfiguraçõeserecursosdoprojetoWebContent/WEB-INF/lib/-bibliotecas.jarWebContent/WEB-INF/classes/-arquivoscompiladossãocopiadosparacá

Resumofinaldaspastas

4.3ANÁLISEDORESULTADOFINAL 51

Page 61: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

META-INF

ApastaMETA-INFéopcionalmaségeradapeloEclipse.Éondeficaoarquivodemanifesto

comousadoemarquivos.jar.

Para criarmos as nossas páginas, precisamos utilizar uma linguagem que consiga ser interpretadapelosnavegadores.EssalinguageméaHTML(HypertextMarkupLanguage).

Comoopróprionomediz,elaéumalinguagemdemarcação,oquesignificaqueelaécompostaportagsquedefinemocomportamentodapáginaqueseestácriando.Essastagsdizemcomoapáginaserávisualizada, através da definição dos componentes visuais que aparecerão na tela. É possível exibirtabelas,parágrafos,blocosdetexto,imagenseassimpordiante.

TodoarquivoHTMLdeveconteraextensão.html,eseuconteúdodeveestardentrodatag<html>.

EmumHTMLbemformado,todasastagsquesãoabertastambémsãofechadas,dessaforma,todooseucódigonumarquivo .html ficarádentrode<html> e</html>.Alémdisso, podemos também

definiralgunsdadosdecabeçalhosparanossapágina,comoporexemplo,otítuloqueserácolocadonajaneladonavegador,atravésdastags<head>e<title>:

<html><head><title>Títuloquevaiaparecernonavegador</title></head></html>

Para escrevermos algo que seja exibido dentro do navegador, no corpo da nossa página, bastacolocarmosatag<body>dentrode<html>,comoaseguir:

<html><body>Textoquevaiaparecernocorpodapágina</body></html>

4.4CRIANDONOSSASPÁGINASEHTMLBÁSICO

52 4.4CRIANDONOSSASPÁGINASEHTMLBÁSICO

Page 62: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

VamostestarnossasconfiguraçõescriandoumarquivoHTMLdeteste.

1. CrieoarquivoWebContent/index.htmlcomoseguinteconteúdo:

<html><head><title>Projetofj21-agenda</title></head><body><h1>Primeirapáginadoprojetofj21-agenda</h1></body></html>

2. Inicie(oureinicie)oTomcatclicandonobotãodeplaynaabaServers.

3. Acesse pelo navegador (nas máquinas da caelum existe um Firefox instalado):http://localhost:8080/fj21-agenda/index.html

Testetambémaconfiguraçãodowelcome-filenoweb.xml:http://localhost:8080/fj21-agenda/

SefosseocasodecriarumaaplicaçãowebsemutilizaroplugindoTomcat,precisaríamoscolocarnossaaplicaçãodentrodoTomcatmanualmente.

Dentro do diretório do Tomcat, há um diretório chamado webapps. Podemos colocar nossasaplicaçõesdentrodessediretório,cadaumadentrodeumdiretórioespecífico.Onomedodiretórioseráonomedocontextodaaplicação.

Por exemplo, para colocar nossa aplicação fj21-agenda no Tomcat manualmente, basta copiar oconteúdododiretórioWebContentparaumdiretóriochamado,porexemplo,agenda dentrodesse

Agoraéamelhorhoradeaprenderalgonovo

4.5EXERCÍCIOS:PRIMEIRAPÁGINA

4.6PARASABERMAIS:CONFIGURANDOOTOMCATSEMOPLUGIN

4.5EXERCÍCIOS:PRIMEIRAPÁGINA 53

Page 63: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

diretóriowebappsdoTomcat.Pronto,oTomcatserviráanossaaplicaçãocomocontextoagenda.ParaqueoTomcatsirvanossaaplicaçãonocontexto/,bastacolocarnossaaplicaçãodentrodeumdiretório

chamadoROOT.

DevidoaofocodocursonãosernoHTML,nãomostraremosafundoastagsdoHTML.Noentanto,abaixoestáumalistacomalgumasdastagsmaiscomunsdoHTML:

h1 -h6:definecabeçalhos,doh1 aoh6, ondemenoronúmero,maior a importância do

cabeçalho;a:criaumlinkparaoutrapágina,ouparaalgumpontodamesmapágina;

p:definequeotextodentrodelaestaráemumparágrafo;

ul:criaumalistadeelementos;

li:criaumnovoitemnumalistadeelementos;

input:colocaumcontroledeformulárionatela(caixadetexto,botão,radiobuttonetc.)

table:defineumatabela;

tr:colocadadentrodeumtableparadefinirumalinhadatabela;

td:colocadadentrodeumtrparadefinirumacélula;

TUTORIALDEHTML

Para um tutorial completo sobre HTML, recomendamos uma visita ao site da MozillaDeveloper Network, que possui referências das tags e exemplos de uso:https://developer.mozilla.org/pt-BR/docs/Web/HTML

Você também pode visitar o tutorial de HTML da W3schools.com:http://www.w3schools.com/html/

4.7ALGUMASTAGSHTML

54 4.7ALGUMASTAGSHTML

Page 64: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

EditoraCasadoCódigocomlivrosdeumaformadiferente

4.7ALGUMASTAGSHTML 55

Page 65: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO5

"Vivemostodossobomesmocéu,masnemtodostemosomesmohorizonte."--KonradAdenauer

Aotérminodessecapítulo,vocêserácapazde:

fazercomqueumaclassesejaacessívelvianavegador;criarpáginascontendoformulários;recebereconverterparâmetrosenviadosporumapágina;distinguirosmétodosHTTP;executarsuaslógicaseregrasdenegócio.

Quando aWeb surgiu, seu objetivo era a troca de conteúdos através, principalmente, de páginasHTMLestáticas.EramarquivosescritosnoformatoHTMLedisponibilizadosemservidoresparaseremacessadosnosnavegadores.Imagens,animaçõeseoutrosconteúdostambémeramdisponibilizados.

MaslogoseviuqueaWebtinhaumenormepotencialdecomunicaçãoeinteraçãoalémdaexibiçãodesimplesconteúdos.Paraatingiressenovoobjetivo,porém,páginasestáticasnãoseriamsuficientes.EraprecisoservirpáginasHTMLgeradasdinamicamentebaseadasnasrequisiçõesdosusuários.

Hoje,boapartedoqueseacessanaWeb(portais,blogs,homebankingsetc)ébaseadoemconteúdodinâmico.Ousuáriorequisitaalgoaoservidorque,porsuavez,processaessarequisiçãoedevolveumarespostanovaparaousuário.

Umadasprimeirasideiasparaesses"geradoresdinâmicos"depáginasHTMLfoifazeroservidorWeb invocar um outro programa externo em cada requisição para gerar oHTML de resposta. Era ofamosoCGIquepermitiaescreverpequenosprogramasparaapresentarpáginasdinâmicasusando,porexemplo,Perl,PHP,ASPeatéCouC++.

Na plataforma Java, a primeira e principal tecnologia capaz de gerar páginas dinâmicas são asServlets, que surgiram no ano de 1997. Hoje, a versão mais encontrada no mercado é baseada nasversões2.x,maisespecificamentea2.4(partedoJ2EE1.4)ea2.5(partedoJavaEE5).Aúltimaversãodisponível é a versão 4.0.3 lançada emAgosto de 2019. Já o JavaEE está na versão 8, lançada emSetembrode2017.

SERVLETS

5.1PÁGINASDINÂMICAS

56 5SERVLETS

Page 66: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

AsServletssãoa primeira formaqueveremosde criar páginas dinâmicas com Java.Usaremos apróprialinguagemJavaparaisso,criandoumaclassequeterácapacidadedegerarconteúdoHTML.Onome"servlet"vemdaideiadeumpequenoservidor(servidorzinho,eminglês)cujoobjetivoéreceberchamadasHTTP,processá-lasedevolverumarespostaaocliente.

Umaprimeiraideiadaservletseriaquecadaumadelaséresponsávelporumapágina,sendoqueelalêdadosdarequisiçãodoclienteerespondecomoutrosdados(umapáginaHTML,umaimagemGIFetc).ComonoJavatentamossemprequepossíveltrabalharorientadoaobjetos,nadamaisnaturalqueumaservletsejarepresentadacomoumobjetoapartirdeumaclasseJava.

Cada servlet é, portanto, um objeto Java que recebe tais requisições (request) e produz algo(response),comoumapáginaHTMLdinamicamentegerada.

OdiagramaabaixomostratrêsclientesacessandoomesmoservidoratravésdoprotocoloHTTP:

JáconheceoscursosonlineAlura?

5.2SERVLETS

5.2SERVLETS 57

Page 67: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

OcomportamentodasservletsquevamosvernestecapítulofoidefinidonaclasseHttpServletdo

pacotejavax.servlet.

AinterfaceServletéaquedefineexatamentecomoumaservletfunciona,masnãoéoquevamos

utilizar,umavezqueelapossibilitaousodequalquerprotocolobaseadoemrequisiçõeserespostas,enãoespecificamenteoHTTP.

Paraescrevermosumaservlet,criamosumaclasseJavaqueestendaHttpServlet e sobrescreva

ummétodo chamado service. Essemétodo será o responsável por atender requisições e gerar as

respostasadequadas.Suaassinatura:

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{...}

Reparequeométodorecebedoisobjetosquerepresentam,respectivamente,arequisiçãofeitapelousuário e a resposta que será exibida no final. Veremos que podemos usar esses objetos para obterinformaçõessobrearequisiçãoeparaconstruirarespostafinalparaousuário.

Nosso primeiro exemplo de implementação dométodo service não executa nada de lógica e

apenasmostraumamensagemestáticadebemvindoparaousuário.Paraisso,precisamosconstruirarespostaqueaservletenviaráparaocliente.

É possível obter um objeto que represente a saída a ser enviada ao usuário através do métodogetWriterdavariávelresponse.E,apartirdisso,utilizarumPrintWriterparaimprimiralgona

respostadocliente:

publicclassOiMundoextendsHttpServlet{protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{

PrintWriterout=response.getWriter();

//escreveotextoout.println("<html>");out.println("<body>");out.println("Primeiraservlet");out.println("</body>");out.println("</html>");}}

OúnicoobjetivodaservletacimaéexibirumamensagemHTMLsimplesparaosusuáriosquearequisitarem.MasnotecomoseriamuitofácilescreveroutroscódigosJavamaispoderososparagerarasStringsdoHTMLbaseadaseminformaçõesdinâmicasvindas,porexemplo,deumbancodedados.

58 5.2SERVLETS

Page 68: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

SERVLETXCGI

Diversasrequisiçõespodemserfeitasàmesmaservletaomesmotempoemumúnicoservidor.Porisso,elaémaisrápidaqueumprogramaCGIcomumquenãopermitiaisso.AespecificaçãodeservletscitaalgumasvantagensemrelaçãoaoCGI.

Ficanamemóriaentrerequisições,nãoprecisaserreinstanciada;OníveldesegurançaepermissãodeacessopodesercontroladoemJava;emCGI,cadaclienteérepresentadoporumprocesso,enquantoquecomServlets,cadaclienteérepresentadoporumalinhadeexecução.

Esse capítulo está focado naHttpServlet, um tipo que gera aplicaçõesWeb baseadas no

protocoloHTTP,masvalelembrarqueaAPInãofoicriadasomenteparaesteprotocolo,podendoserestendidaparaoutrosprotocolostambémbaseadosemrequisiçõeserespostas.

Acabamos de definir uma Servlet, mas como vamos acessá-la pelo navegador? Qual o endereçopodemos acessar para fazermos com que ela execute? O container não tem como saber essasinformações,anãoserquedigamosissoparaele.Paraisso,vamosfazerummapeamentodeumaURLespecíficaparaumaservletatravésdoarquivoweb.xml,queficadentrodoWEB-INF.

Uma vez que chamar a servlet pelo pacote e nome da classe acabaria criandoURLs estranhas ecomplexas,écomummapear,porexemplo,umaservletcomonoexemplo,chamadaOiMundoparao

nomeprimeiraServlet.

Começamoscomadefiniçãodaservletemsi,dentrodatag<servlet>:

<servlet><servlet-name>primeiraServlet</servlet-name><servlet-class>br.com.caelum.servlet.OiMundo</servlet-class></servlet>

Em seguida, mapeie nossa servlet para a URL /oi. Perceba que isso acontece dentro da tag

<servlet-mapping> (mapeamentodeservlets)equevocê temque indicarqueestáfalandodaquela

servletquedefinimoslogoacima:passamosomesmoservlet-nameparaomapeamento.

<servlet-mapping><servlet-name>primeiraServlet</servlet-name><url-pattern>/oi</url-pattern></servlet-mapping>

Portanto,sãonecessáriosdoispassosparamapearumaservletparaumaURL:

5.3MAPEANDOUMASERVLETNOWEB.XML

5.3MAPEANDOUMASERVLETNOWEB.XML 59

Page 69: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Definironomeeclassedaservlet;Usandoonomedaservlet,definiraURL.

AservletpodeseracessadaatravésdaseguinteURL:

http://localhost:8080/fj21-agenda/oi

Assimqueo arquivoweb.xml e a classe da servlet de exemplo forem colocados nos diretórios

corretos,bastaconfiguraroTomcatparautilizarodiretóriodebasecomopadrãoparaumaaplicaçãoWeb.

Atag<url-pattern>tambémtedáaflexibilidadededisponibilizarumaservletatravésdevárias

URLsdeumcaminho,porexemploocódigoabaixofarácomquequalquerendereçoacessadodentrode/oisejainterpretadopelasuaservlet:

<servlet-mapping><servlet-name>primeiraServlet</servlet-name><url-pattern>/oi/*</url-pattern></servlet-mapping>

Vocêaindapodeconfigurar"extensões"paraassuasservlets,porexemplo,omapeamentoabaixofarácomquesuaservletsejachamadaporqualquerrequisiçãoqueterminecom.php:

<servlet-mapping><servlet-name>primeiraServlet</servlet-name><url-pattern>*.php</url-pattern></servlet-mapping>

Reparequenãocriamosdiretórionenhumnanossaaplicação(excetoopacoteparaanossaclasseServlet). Ou seja, o mapeamento da servlet não tem relação alguma com um diretório físico naaplicação. Essemapeamento é apenas um nome atribuído, virtual, que é utilizado para acessarmos aaplicação.

Maissobreourl-pattern

5.4AESTRUTURADEDIRETÓRIOS

60 5.4AESTRUTURADEDIRETÓRIOS

Page 70: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

1. ParacriarnossasServletsprecisamosusarasclasseseinterfacesquepertencemaAPIdeServlet,ouseja, precisamos adicionar o jar dessa especificação ao Classpath. Se o projeto foi criadocorretamente o Tomcat 9 faz parte do nosso Classpath e como consequência todas as suasdependênciastambém.Dessaformapodemosusarojarquevemjuntodele:

CasooTomcat9nãofaçapartedonossoClasspathpodemosadicionarmanualmenteadependênciaao nosso projeto. Acesse a pasta 21/projeto-agenda/servlet e copie o arquivo jakarta.servlet-api-4.X.X.jarecoledentrodonossoprojeto,nodiretórioWebContent/WEB-INF/lib:

VocêpodetambémfazerocursodatadessaapostilanaCaelum

5.5EXERCÍCIOS:PRIMEIRASERVLET

5.5EXERCÍCIOS:PRIMEIRASERVLET 61

Page 71: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

2.CrieaservletOiMundonopacotebr.com.caelum.servlet.EscolhaomenuFile,New,Class(maisumavez,aproveiteparaaprenderteclasdeatalho).

EstendaHttpServlet:

publicclassOiMundoextendsHttpServlet{}

UtilizeoCTRL+SHIFT+OparaimportarHttpServlet.

Para escrever a estrutura do método service, dentro da classe, escreva apenas service e dêCtrl+espaço:oEclipsegerapravocêométodo.

62 5.5EXERCÍCIOS:PRIMEIRASERVLET

Page 72: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

ATENÇÃO: Cuidado para escolher corretamente a versão de service que recebeHttpServletRequest/Response.

Aanotação@Overrideserveparanotificarocompiladorqueestamossobrescrevendoométodo

servicedaclassemãe.Se,poracaso,errarmosonomedométodoou trocarmosaordemdos

parâmetros,ocompiladorvaireclamarevocêvaiperceberoerroaindaemtempodecompilação.

Ométodogeradodeveseresse.Troqueosnomesdosparâmetrosarg0earg1comoabaixo:

@Overrideprotectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{}

Escreva dentro do método service sua implementação. Por enquanto, queremos apenas que

nossaServletmonteumapáginaHTMLsimplesparatestarmos.

Cuidadoemtirarachamadaaosuper.serviceantesereparequeadeclaraçãodométodojáfoi

feitanopassoanterior.

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{

PrintWriterout=response.getWriter();

out.println("<html>");out.println("<head>");out.println("<title>PrimeiraServlet</title>");out.println("</head>");out.println("<body>");out.println("<h1>OimundoServlet!</h1>");out.println("</body>");out.println("</html>");}

3.Abraoarquivoweb.xmlecliquenaabaSourcenaparteinferiordoeditordecódigo.Dentrodatag<web-app>,mapeieaURL/oiparaaservletOiMundo.AproveiteoautocompletardoEclipseecuidadoaoescreveronomedaclasseedopacote.

5.5EXERCÍCIOS:PRIMEIRASERVLET 63

Page 73: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<servlet><servlet-name>servletOiMundo</servlet-name><servlet-class>br.com.caelum.servlet.OiMundo</servlet-class></servlet>

<servlet-mapping><servlet-name>servletOiMundo</servlet-name><url-pattern>/oi</url-pattern></servlet-mapping>

4. Reinicie o Tomcat clicando no botão verde na aba Servers. 5. Teste a urlhttp://localhost:8080/fj21-agenda/oi

Existemdiversoserroscomunsnosexercíciosanteriores.Aquivãoalgunsdeles:

EsquecerdabarrainicialnoURLpattern:

<url-pattern>oi</url-pattern>

5.6ERROSCOMUNS

64 5.6ERROSCOMUNS

Page 74: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Nessecaso,umaexceçãoaconteceránomomentoemqueotomcatforinicializado:

Digitarerradoonomedopacotedasuaservlet:

<servlet-class>br.caelum.servlet.OiMundo</servlet-class>

Esquecerdecolocaronomedaclassenomapeamentodaservlet:

<servlet-class>br.com.caelum.servlet</servlet-class>

Como foi visto no exercício anterior, criar Servlets usando o Java EE 5 é um processo muitotrabalhoso. Um dos grandes problemas é que temos que configurar cada um de nossas Servlets noweb.xml e se quisermos acessar essa servlet de maneiras diferentes, temos que criar váriosmapeamentosparaamesmaservlet,oquepodecomo tempo tornar-seumproblemadevidoadifícilmanutenção.

ApartirdaespecificaçãoServlets3.0,que fazpartedoJavaEE6,podemosconfiguraramaneiracomovamosacessaranossaServletdemaneiraprogramática,utilizandoanotaçõessimples.

5.7FACILIDADESDASSERVLETS3.0

5.7FACILIDADESDASSERVLETS3.0 65

Page 75: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Demodogeral,nãoémaisprecisoconfigurarasnossasServletsnoweb.xml,sendosuficienteusaraanotação@WebServletapenas:

@WebServlet("/oi")publicclassOiServlet3extendsHttpServlet{...}

IssoéequivalenteaconfiguraraServletacimacomaurl-patternconfiguradacomo/oi.

Naanotação@WebServlet,podemoscolocaraindaumparâmetroopcionalchamadoname que

defineumnomeparaaServlet(equivalenteaoservlet-name).Senãodefinirmosesseatributo,por

padrão,onomedaServletéonomecompletodaclassedasuaServlet,tambémconhecidocomoFullyQualifiedName.

SequisermosquenossaServletsejaacessadoatravésdeapenasumaURL,recomenda-sedefiniraURLdiretamentenoatributovaluecomonoexemploacima.Masseprecisarmosdefinirmaisdeuma

URLparaacessaraServlet,podemosutilizaroatributourlPatternsepassarumvetordeURLs:

@WebServlet(name="MinhaServlet3",urlPatterns={"/oi","/ola"})publicclassOiServlet3extendsHttpServlet{...}

É bom reforçar que, mesmo a Servlet estando anotado com @WebServlet() , ele deve

obrigatoriamenterealizarumextendsaclassejavax.servlet.http.HttpServlet.

ARQUIVOWEB.XML

Dentro da tag <web-app> no web.xml, existe um novo atributo chamado metadata-

complete. Nesse atributo podemos configurar se nossas classes anotadas com @WebServlet

serãoprocuradaspeloservidordeaplicação.Sedefinirmoscomotrueasclassesanotadasserão

ignoradas.

SenãodefinirmosoudefinirmoscomofalseasclassesqueestiveremnoWEB-INF/classes

ouemalgum.jardentroWEB-INF/libserãoexaminadaspeloservidordeaplicação.

66 5.7FACILIDADESDASSERVLETS3.0

Page 76: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Mesmo sendo uma prática questionada por alguns desenvolvedores, podemos passar parâmetrosprogramaticamenteparaasServletsnasuainicializaçãoesemprecisardoarquivoweb.xml.Bastausaraanotação@WebInitParam(), para declarar cadaparâmetronopadrão chave/valor e depois passá-los

dentrodeumvetorparaapropriedadeinitParamsdaanotação@WebServlet():

@WebServlet(name="OiServlet3",urlPatterns={"/oi"},initParams={@WebInitParam(name="param1",value="value1"),@WebInitParam(name="param2",value="value2")})publicclassOiServlet3{...}

Pararecuperá-losdentrodaServlettemostrêsestratégias:

Usandoasobrecargadométodoinit()dasServlets:

//códigoomitidoprivateStringparametro1;privateStringparametro2;

@Overridepublicvoidinit(ServletConfigconfig)throwsServletException{super.init(config);this.parametro1=config.getInitParameter("param1");this.parametro2=config.getInitParameter("param2");}

EmqualqueroutrométododaServletpormeiodeumobjetodaclasseServletConfig:

publicvoidservice(HttpServletRequestrequest,

Seuslivrosdetecnologiaparecemdoséculopassado?

5.8PARASABERMAIS:WEBSERVLETEINITPARAMANNOTATION

5.8PARASABERMAIS:WEBSERVLETEINITPARAMANNOTATION 67

Page 77: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

HttpServletResponseresponse)throwsServletException,IOException{

response.setContentType("text/html");PrintWriterout=response.getWriter();

out.println("<h2>ExemplocomInitParamServlet</h2>");

ServletConfigconfig=getServletConfig();

Stringparametro1=config.getInitParameter("param1");out.println("Valordoparâmetro1:"+parametro1);

Stringparametro2=config.getInitParameter("param2");out.println("<br>Valordoparâmetro1:"+parametro2);

out.close();}

OuusandoométodogetServletConfig()comgetInitParameter()diretonaopçãodesaída:

out.println("Valordoparâmetro1:"+getServletConfig().getInitParameter("param1"));

AodesenvolverumaaplicaçãoWeb,sempreprecisamosrealizaroperaçõesnoladodoservidor,comdadosinformadospelousuário,sejaatravésdeformuláriosousejaatravésdaURL.

Porexemplo,paragravarmosumcontatonobancodedados,precisamosdonome,e-mail,endereçoeadatadenascimentodele.Temosumapáginacomumformulárioqueousuáriopossapreenchereaoclicaremumbotãoessesdadosdevem,dealgumaforma,serpassadosparaumServlet.Jásabemosquea Servlet responde por uma determinada URL (através do url-pattern/v2.5 ou do urlPatterns/v3.0),portanto,sóprecisamosindicarqueaoclicarnobotãodevemosenviarumarequisiçãoparaessaServlet.

Para isso, vamos criar uma página HTML, chamada adiciona-contato.html , contendo um

formulárioparapreenchermososdadosdoscontatos:

<html><body><formaction="adicionaContato">Nome:<inputtype="text"name="nome"/><br/>E-mail:<inputtype="text"name="email"/><br/>Endereço:<inputtype="text"name="endereco"/><br/>DataNascimento:<inputtype="text"name="dataNascimento"/><br/>

<inputtype="submit"value="Gravar"/></form></body></html>

Essecódigopossuiumformulário,determinadopelatag<form>.Oatributoactionindicaqual

endereçodeveserchamadoaosubmeteroformulário,aoclicarnobotãoGravar.Nessecaso,estamosapontandooactionparaumendereçoqueseráumaServletquejávamoscriar.

5.9ENVIANDOPARÂMETROSNAREQUISIÇÃO

68 5.9ENVIANDOPARÂMETROSNAREQUISIÇÃO

Page 78: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Aoacessarapáginaadiciona-contato.html,oresultadodeverásersimilaràfiguraabaixo:

Pararecebermososvaloresqueforampreenchidosnatelaesubmetidos,criaremosumaServlet,

cujafunçãoseráreceberdealgumamaneiraessesdadoseconvertê-los,senecessário.

DentrodométodoservicedanossaServletparaadiçãodecontatos,vamosbuscarosdadosque

foramenviadosnarequisição.Parabuscarmosessesdados,precisamosutilizaroparâmetrorequestdométodoservice chamando ométodo getParameter("nomeDoParametro"), onde o nome do

parâmetroéomesmonomedoinputquevocêquerbuscarovalor.IssovairetornarumaString

comovalordoparâmetro.Casonãoexistaoparâmetro,seráretornadonull:

StringvalorDoParametro=request.getParameter("nomeDoParametro");

OfatodeserdevolvidaumaStringnostrazumproblema,pois,adatadenascimentodocontato

está criada como um objeto do tipo Calendar. Então, o que precisamos fazer é converter essaStringemumobjetoCalendar.MasaAPIdoJavaparatrabalharcomdatasnãonospermitefazer

issodiretamente.TeremosqueconverterantesaStringemumobjetodotipojava.util.Datecom

auxíliodaclasseSimpleDateFormat,utilizandoométodoparse,daseguinteforma:

StringdataEmTexto=request.getParameter("dataNascimento");Datedate=newSimpleDateFormat("dd/MM/yyyy").parse(dataEmTexto);

Repare que indicamos também o pattern (formato) com que essa data deveria chegar para nós,atravésdoparâmetropassadonoconstrutordeSimpleDateFormatcomovalordd/MM/yyyy.TemosquetomarcuidadopoisométodoparselançaumaexceçãodotipoParseException.Essaexceção

indicaqueoquefoipassadonadatanãopôdeserconvertidoaopatternespecificado.Comoobjetodotipojava.util.Date que foi devolvido, queremos criar um Calendar. Para isso vamos usar o

métodosetTimedaclasseCalendar,querecebeumDate.

dataNascimento=Calendar.getInstance();dataNascimento.setTime(date);

VamosutilizartambémonossoDAOparagravaroscontatosnobancodedados.Nofinal,anossa

5.10PEGANDOOSPARÂMETROSDAREQUISIÇÃO

5.10PEGANDOOSPARÂMETROSDAREQUISIÇÃO 69

Page 79: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Servletficarádaseguinteforma:

@WebServlet("/adicionaContato")publicclassAdicionaContatoServletextendsHttpServlet{protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException,ServletException{

PrintWriterout=response.getWriter();

//pegandoosparâmetrosdorequestStringnome=request.getParameter("nome");Stringendereco=request.getParameter("endereco");Stringemail=request.getParameter("email");StringdataEmTexto=request.getParameter("dataNascimento");CalendardataNascimento=null;

//fazendoaconversãodadatatry{Datedate=newSimpleDateFormat("dd/MM/yyyy").parse(dataEmTexto);dataNascimento=Calendar.getInstance();dataNascimento.setTime(date);}catch(ParseExceptione){out.println("Errodeconversãodadata");return;//paraaexecuçãodométodo}

//montaumobjetocontatoContatocontato=newContato();contato.setNome(nome);contato.setEndereco(endereco);contato.setEmail(email);contato.setDataNascimento(dataNascimento);

//salvaocontatoContatoDaodao=newContatoDao();dao.adiciona(contato);

//imprimeonomedocontatoquefoiadicionadoout.println("<html>");out.println("<body>");out.println("Contato"+contato.getNome()+"adicionadocomsucesso");out.println("</body>");out.println("</html>");}}

70 5.10PEGANDOOSPARÂMETROSDAREQUISIÇÃO

Page 80: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

1. Comovamosprecisargravarcontatos,precisaremosdasclassesparatrabalharcombancodedadosque criamos no capítulo de JDBC. Para isso, deixamos disponível um arquivo zip contendo asclassesnecessáriasquecriamosanteriormente.

NoEclipse,selecioneoprojetofj21-agendaevánomenuFile->Import

DentrodajaneladeImport,escolhaGeneral->ArchiveFileecliqueemNext:

No campoFromarchive file clique emBrowse, selecioneo arquivo /21/projeto-agenda/dao-modelo.zipecliqueemFinish

vejaque,napastaWEB-INF/lib encontram-se2driversMySQL.Verifiquequal a versãoque

vocêestáutilizando,eremovaodriverquevocênãoprecisar.

EMCASA

Casovocêesteja fazendoemcasa,vocêpodeusarexatamenteasmesmasclassescriadasdurante os exercícios do capítulo de JDBC, mas terá que fazer uma mudança na classeConnectionFactory(volteaocapítulo2,noboxsobreoClass.forName.NãoesqueçadecopiartambémoDriverdoMySQL.

2. Temosquecriarapáginaquepermitiráaosusuárioscadastraroscontatos

VánomenuFile->New->Other.

Agoraéamelhorhoradeaprenderalgonovo

5.11 EXERCÍCIOS: CRIANDO FUNCIONALIDADE PARA GRAVARCONTATOS

5.11EXERCÍCIOS:CRIANDOFUNCIONALIDADEPARAGRAVARCONTATOS 71

Page 81: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

EscolhaWeb->HTMLPageouHTMLFileecliqueNext:

Chame o arquivo de adiciona-contato.html e clique emFinish (garanta que o arquivo estejadentrododiretórioWebContent):

EssearquivoHTMLdeveráteroseguinteconteúdo(cuidadocomonomedosinputs):

<html><body><h1>AdicionaContatos</h1><hr/><formaction="adicionaContato">Nome:<inputtype="text"name="nome"/><br/>E-mail:<inputtype="text"name="email"/><br/>Endereço:<inputtype="text"name="endereco"/><br/>DataNascimento:<inputtype="text"name="dataNascimento"/><br/>

<inputtype="submit"value="Gravar"/></form>

72 5.11EXERCÍCIOS:CRIANDOFUNCIONALIDADEPARAGRAVARCONTATOS

Page 82: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

</body></html>

Acessenonavegadoroendereço:

http://localhost:8080/fj21-agenda/adiciona-contato.html

3. PrecisamoscriaraServletquegravaráocontatonobancodedados:

Crie uma nova Servlet no pacote br.com.caelum.agenda.servlet chamado

AdicionaContatoServletcomoseguintecódigo.

Cuidadoaoimplementaressaclasse,queégrandeecomplicada.

UseoCtrl+Shift+Oparaajudarnosimports.AclasseDatedeveserdejava.utileaclasse

ParseException,dejava.text.

@WebServlet("/adicionaContato")publicclassAdicionaContatoServletextendsHttpServlet{protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException,ServletException{//buscaowriterPrintWriterout=response.getWriter();

//buscandoosparâmetrosnorequestStringnome=request.getParameter("nome");Stringendereco=request.getParameter("endereco");Stringemail=request.getParameter("email");StringdataEmTexto=request.getParameter("dataNascimento");CalendardataNascimento=null;

//fazendoaconversãodadatatry{Datedate=newSimpleDateFormat("dd/MM/yyyy").parse(dataEmTexto);dataNascimento=Calendar.getInstance();dataNascimento.setTime(date);}catch(ParseExceptione){out.println("Errodeconversãodadata");return;//paraaexecuçãodométodo}

5.11EXERCÍCIOS:CRIANDOFUNCIONALIDADEPARAGRAVARCONTATOS 73

Page 83: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

//montaumobjetocontatoContatocontato=newContato();contato.setNome(nome);contato.setEndereco(endereco);contato.setEmail(email);contato.setDataNascimento(dataNascimento);

//salvaocontatoContatoDaodao=newContatoDao();dao.adiciona(contato);

//imprimeonomedocontatoquefoiadicionadoout.println("<html>");out.println("<body>");out.println("Contato"+contato.getNome()+"adicionadocomsucesso");out.println("</body>");out.println("</html>");}}

UTILIZANDOASERVLETV2.5

Se ainda estivéssemos utilizando a versão 2.5 da Servlet, precisaríamos fazer o seguintemapeamentonoweb.xml:

<servlet><servlet-name>AdicionaContato</servlet-name><servlet-class>br.com.caelum.agenda.servlet.AdicionaContatoServlet</servlet-class></servlet>

<servlet-mapping><servlet-name>AdicionaContato</servlet-name><url-pattern>/adicionaContato</url-pattern></servlet-mapping>

Reinicieoservidor,paraqueanovaServletsejareconhecido

Acesse novamente no navegador a URL http://localhost:8080/fj21-agenda/adiciona-contato.html

PreenchaoformulárioecliqueemGravar.Oresultadodevesersemelhanteàimagemaseguir:

74 5.11EXERCÍCIOS:CRIANDOFUNCIONALIDADEPARAGRAVARCONTATOS

Page 84: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Verifiquenobancodedadosseodadorealmentefoiadicionadocomsucesso.

Repare que no exercício anterior, ao clicarmos no botão salvar, todos os dados que digitamos noformulário aparecem na URL da página de sucesso. Isso acontece porque não definimos no nossoformulárioaformacomqueosdadossãoenviadosparaoservidor,atravésdoatributomethodparao

<form>daseguinteforma:

<formaction="adicionaContato"method="POST">

Comonão tínhamosdefinido,porpadrãoentãoéusadoométodoGET,que indicaqueosvaloresdosparâmetrossãopassadosatravésdaURLjuntodosnomesdosmesmos,separadospor&,comoem:nome=Adriano&[email protected]

Podemos tambémdefinir ométodoparaPOST e, dessa forma, os dados sãopassadosdentrodo

corpodoprotocoloHTTP,semaparecernaURLqueémostradanonavegador.

Podemos, além de definir no formulário como os dados serão passados, também definir quaismétodosHTTPnossaservletaceitará.

OmétodoserviceaceitatodososmétodosHTTP,portanto,tantoométodoGETquantooPOST.

Para especificarmos como trataremos cada método, temos que escrever os métodos doGet e/ou

doPostnanossaservlet:

voiddoGet(HttpServletRequestreq,HttpServletResponseres);

voiddoPost(HttpServletRequestreq,HttpServletResponseres);

OUTROSMÉTODOSHTTP

AlémdoGETedoPOST,oprotocoloHTTPpossui aindamais7métodos:PUT,DELETE,HEAD,TRACE,CONNECT,OPTIONSePATCH.

MuitaspessoasconhecemapenasoGETePOST,pois,sãoosúnicosqueHTML4suporta.

OqueseráquevaiacontecersealgumSQLdonossoDAOcontivererrodesintaxeeocomandonãopuderserexecutado?Seráquevaiaparecerumamensagemagradávelparaousuário?

Naverdade,casoaconteçaumerrodentrodanossaServletastacktracedaexceçãoocorridaserá

mostradaemumatelapadrãodocontainer.Oproblemaéqueparaousuáriocomum,amensagemde

5.12GET,POSTEMÉTODOSHTTP

5.13TRATANDOEXCEÇÕESDENTRODASERVLET

5.12GET,POSTEMÉTODOSHTTP 75

Page 85: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

errodoJavanãofaráomenorsentido.Oidealseriamostrarmosumapáginadeerrodizendo:"Umerroocorreu"ecominformaçõesdecomonotificaroadministrador.

Parafazermosisso,bastaconfigurarmosnossaaplicaçãodizendoque,casoaconteçaumaException,uma página de erro deverá ser exibida. Essa configuração é feita no web.xml, com a seguintedeclaração:

<error-page><exception-type>java.lang.Exception</exception-type><location>/erro.html</location></error-page>

Alémdetratarmosasexceçõesquepodemacontecernanossaaplicação,podemostambémtrataroscódigos de erro HTTP, como por exemplo, 404, que é o erro dado quando se acessa uma páginainexistente.Paraissobastafazermosadeclaraçãonoweb.xml:

<error-page><error-code>404</error-code><location>/404.html</location></error-page>

WRAPPINGEMSERVLETEXCEPTION

Caso aconteça uma exceção que seja do tipo checada (não filha de RuntimeException),

tambémteríamosque repassá-laparacontainer.Noentanto,ométodoservice só nospermite

lançarServletExceptioneIOException.

Para podermos lançar outra exceção checked, precisamos escondê-la em umaServletException,comoaseguir:

try{//códigoquepodelançarSQLException}catch(SQLExceptione){thrownewServletException(e);}

Essa técnica é conhecida como wrapping de exceptions. O container, ao receber aServletException,vaidesembrulharaexceptioninternaetratá-la.

76 5.13TRATANDOEXCEÇÕESDENTRODASERVLET

Page 86: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

1. Vamoscriarumapáginaparamostraramensagemgenéricadetratamento:

CrieumnovoHTMLchamadoerro.htmlcomoseguinteconteúdo:

<html><body>Umerroocorreu!</body></html>

Adicioneadeclaraçãodapáginadeerronoweb.xml:

<error-page><exception-type>java.lang.Exception</exception-type><location>/erro.html</location></error-page>

AltereousuáriodeacessoaobanconaclasseConnectionFactoryderootparaalgumoutrousuárioquenãoexista,porexemplo,toor.

Reinicieoservidor,paraqueasalteraçõestenhamefeito

AcessenonavegadoraURLhttp://localhost:8080/fj21-agenda/adiciona-contato.html

PreenchaoformulárioecliqueemGravar,oresultadodevesersemelhanteàimagemaseguir:

EditoraCasadoCódigocomlivrosdeumaformadiferente

5.14EXERCÍCIO:TRATANDOEXCEÇÕESECÓDIGOSHTTP

5.14EXERCÍCIO:TRATANDOEXCEÇÕESECÓDIGOSHTTP 77

Page 87: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

AlterenovamenteousuáriodeacessoaobanconaclasseConnectionFactorypararoot.

1. Vamoscriarumapáginaparaserexibidaquandoousuárioacessaralgoinexistente:

CrieumnovoHTMLchamado404.htmlcomoseguinteconteúdo:

<html><body>Apáginaacessadanãoexiste.</body></html>

Adicioneadeclaraçãodapáginanoweb.xml:

<error-page><error-code>404</error-code><location>/404.html</location></error-page>

Reinicienovamenteoservidor;

Acesse no navegador uma URL inexistente no projeto, por exemplo, http://localhost:8080/fj21-agenda/naoexiste.html:

TodaServletdevepossuirumconstrutorsemargumentosparaqueocontainerpossacriá-lo.Apósacriação,oservletcontainerinicializaaServletcomométodoinit(ServletConfigconfig)eousa

durante todoo seuperíodoativo, atéquevaidesativá-lo atravésdométododestroy(), para então

liberaroobjeto.

ÉimportanteperceberqueasuaServletseráinstanciadoumaúnicavezpelocontainereesseúnicoobjetoseráusadoparaatenderatodasasrequisiçõesdetodososclientesemthreadsseparadas.Aliás,éjustoissoquetrazumamelhoriaemrelaçãoaosCGIcomunsquedisparavamdiversosprocessos.

NainicializaçãodeumaServlet,quandoparâmetrospodemserlidosevariáveiscomunsatodasasrequisiçõesdevemserinicializadas,éumbommomento,porexemplo,paracarregararquivosdiversosdeconfiguraçõesdaaplicação:

voidinit(ServletConfigconfig);

5.15INITEDESTROY

78 5.15INITEDESTROY

Page 88: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Nafinalização,devemosliberarpossíveisrecursosqueestejamossegurando:

voiddestroy();

Osmétodosinit edestroy, quando reescritos, sãoobrigados a chamarosuper.init() e

super.destroy() respectivamente. Isso acontece pois um método é diferente de um construtor.

Quando estendemos uma classe e criamos o nosso próprio construtor da classe filha, ela chama oconstrutor da classe pai sem argumentos, preservando a garantia da chamada de um construtor. Omesmonãoacontececomosmétodos.

Supondoqueométodoinit(oudestroy)executaalgumatarefafundamentalemsuaclassepai,

sevocêesquecerdechamarosuper,teráproblemas.

OexemploaseguirmostraumaServlet implementandoosmétodosde inicializaçãoefinalização.Osmétodosinitedestroypodemserbemsimples(lembre-sequesãoopcionais):

@WebServlet("/minhaServlet")publicclassMinhaServletextendsHttpServlet{

publicvoidinit(ServletConfigconfig)throwsServletException{super.init(config);log("Iniciandoaservlet");}

publicvoiddestroy(){super.destroy();log("Destruindoaservlet");}

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException,ServletException{//códigodoseumétodoservice}}

DeacordocomaespecificaçãodeServlets,porpadrão,existeumaúnicainstânciadecadaServletdeclarada.AochegarumarequisiçãoparaaServlet,umanovaThreadéabertasobreaquelainstância

quejáexiste.

Isso significa que, se colocássemos em nossa Servlet uma variável de instância, ela seriacompartilhadaentretodasasthreadsqueacessamessaServlet!Emoutraspalavras,seriacompartilhadoentre todasasrequisiçõese todososclientesenxergariamomesmovalor.Provavelmentenãoéoquequeremosfazer.

UmexemplosimplesparanosauxiliarenxergarissoéumaServletcomumavariávelparacontaraquantidadederequisições:

5.16UMAÚNICAINSTÂNCIADECADASERVLET

5.16UMAÚNICAINSTÂNCIADECADASERVLET 79

Page 89: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

@WebServlet("/contador")publicclassContadorextendsHttpServlet{privateintcontador=0;//variaveldeinstância

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{contador++;//acadarequisiçãoamesmavariáveléincrementada

//recebeowriterPrintWriterout=response.getWriter();

//escreveotextoout.println("<html>");out.println("<body>");out.println("Contadoragoraé:"+contador);out.println("</body>");out.println("</html>");}}

QuandoaServlet for inicializada,ovalordocontadorédefinidopara0 (zero).Após isso,acadarequisição que é feita para essa Servlet, devido ao fato da instância ser sempre amesma, a variávelutilizadaparaincrementarserásempreamesma,eporconsequênciaimprimiráonúmeroatualparaocontador.

Sabemosquecompartilharvariáveis entremúltiplasThreadspodenos trazerproblemasgravesdeconcorrência. Se duas threads (no caso, duas requisições)modificarem amesmavariável ao "mesmotempo",podemosterperdadeinformaçõesmesmoemcasossimplescomoodocontadoracima.

Háduassoluçõesparaesseproblema.Aprimeiraseriaimpedirqueduasthreadsacessemaomesmotempoomesmoobjetocrítico;paraisso,podemossincronizarométodoservice.Masissotrariamuitosproblemas de escalabilidade (apenas uma pessoa por vez poderia requisitar minha página). A outrasolução,maissimples,éapenasnãocompartilharobjetosentrethreads.

QuandosefaladeServlets,aboapráticadizparaevitarusaratributoscompartilhados.

80 5.16UMAÚNICAINSTÂNCIADECADASERVLET

Page 90: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

1. ImplementeoscódigosdasseçõesanterioressobreciclodevidaeconcorrênciaemServlets.FaçaaclasseContador e use tambémosmétodosinit edestroy.Oobjetivo é ver naprática os

conceitosdiscutidos.

Imaginesequiséssemoslistarosnossoscontatos,comopoderíamosfazer?Comoatéomomentosóconhecemos Servlet, provavelmente nossa sugestão seria criarmos uma Servlet que faça toda a

listagematravésdeout.println().Mas,seráqueamanutençãodissoseriaagradável?Eseumdia

precisarmos adicionar uma coluna nova na tabela? Teríamos que recompilar classes, e colocarmos aatualizaçãonoar.

Com o decorrer do curso aprenderemos que essa não é a melhor forma de fazermos essafuncionalidade.

JáconheceoscursosonlineAlura?

5.17EXERCÍCIOSOPCIONAIS

5.18DISCUSSÃO:CRIANDOPÁGINASDENTRODEUMASERVLET

5.17EXERCÍCIOSOPCIONAIS 81

Page 91: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO6

"Omaiorprazeréesperarpeloprazer."--GottholdLessing

Nessecapítulo,vocêaprenderá:

OqueéJSP;Suasvantagensedesvantagens;EscreverarquivosJSPcomscriptlets;UsarExpressionLanguage.

Atéagora,vimosquepodemosescreverconteúdodinâmicoatravésdeServlets.Noentanto, se

todahoracriarmosServletsparafazermosessetrabalho,teremosmuitosproblemasnamanutenção

das nossas páginas e também na legibilidade do nosso código, pois sempre aparece código JavamisturadocomcódigoHTML.ImaginetodoumsistemacriadocomServletsfazendoageraçãodo

HTML.

Para não termos que criar todos os nossos conteúdos dinâmicos dentro de classes, misturandofortementeHTMLcomcódigo Java, precisamosusar uma tecnologia que podemos usar oHTMLdeformadireta,equetambémvápossibilitarautilizaçãodoJava.AlgosimilaraoASPePHP.

Essa tecnologiaéoJavaServerPages (JSP).OprimeiroarquivoJSPquevamoscriaréchamadobemvindo.jsp.EssearquivopoderiacontersimplesmentecódigoHTML,comoocódigoaseguir:

<html><body>Bemvindo</body></html>

Assim, fica claro que uma página JSP nadamais é que um arquivo baseado emHTML, com aextensão.jsp.

Dentro de um arquivo JSP podemos escrever também código Java, para que possamos adicionarcomportamentodinâmicoemnossaspáginas,comodeclaraçãodevariáveis,condicionais(if), loops

(for,while)entreoutros.

JAVASERVERPAGES

6.1COLOCANDOOHTMLNOSEUDEVIDOLUGAR

82 6JAVASERVERPAGES

Page 92: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Portanto,vamosescreverumpoucodecódigoJavananossaprimeirapágina.VamosdeclararumavariáveldotipoStringeinicializá-lacomalgumvalor.

<%Stringmensagem="Bemvindo!";%>

Para escrever código Javana suapágina,basta escrevê-lo entre as tags<% e%>.Esse tipode

códigoéchamadodescriptlet.

SCRIPTLET

Scriptletéocódigoescritoentre<%e%>.Essenomeécompostodapalavrascript(pedaço

decódigoemlinguagemdescript)comosufixolet,queindicaalgopequeno.

Comovocêjápercebeu,aSunpossuiessamaniadecolocarosufixoletemseusprodutoscomoosscriptlets,servlets,portlets,midlets,appletsetc...

PodemosavançarmaisumpoucoeutilizarumadasvariáveisjáimplícitasnoJSP:todoarquivoJSPjápossuiumavariávelchamadaout(dotipoJspWriter)quepermite imprimirparaoresponse

atravésdométodoprintln:

<%out.println(nome);%>

A variável out é um objeto implícito na nossa página JSP e existem outras de acordo com a

especificação. Repare também que sua funcionalidade é semelhante ao out que utilizávamos nas

Servletsmassemprecisarmosdeclará-loantes.

Existemaindaoutraspossibilidadespara imprimiroconteúdodanossavariável:podemosutilizarumatalho(muitoparecido,ouigual,aoutraslinguagensdescriptparaaWeb):

<%=nome%><br/>

IssojáéosuficienteparaquepossamosescreveronossoprimeiroJSP.

COMENTÁRIOS

OscomentáriosemumapáginaJSPdevemserfeitoscomooexemploaseguir:

<%--comentárioemjsp--%>

6.1COLOCANDOOHTMLNOSEUDEVIDOLUGAR 83

Page 93: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

1. CrieoarquivoWebContent/bemvindo.jspcomoseguinteconteúdo:

<html><body><%--comentárioemJSPaqui:nossaprimeirapáginaJSP--%>

<%Stringmensagem="BemvindoaosistemadeagendadoFJ-21!";%><%out.println(mensagem);%>

<br/>

<%Stringdesenvolvido="Desenvolvidopor(SEUNOMEAQUI)";%><%=desenvolvido%>

<br/>

<%System.out.println("Tudofoiexecutado!");%></body></html>

1. AcesseaURLhttp://localhost:8080/fj21-agenda/bemvindo.jspnonavegador

VocêpodetambémfazerocursodatadessaapostilanaCaelum

6.2EXERCÍCIOS:PRIMEIROJSP

84 6.2EXERCÍCIOS:PRIMEIROJSP

Page 94: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

2. Ondeapareceuamensagem"Tudofoiexecutado!"?

É muito importante você se lembrar que o código Java é interpretado no servidor, portantoapareceunoconsoledoseuTomcat.

VerifiqueoconsoledoseuTomcat.

Uma vez que podemos escrever qualquer código Java como scriptlet, não fica difícil criar umalistagemdetodososcontatosdobancodedados.

Temos todas as ferramentas necessárias para fazer essa listagem uma vez que já fizemos isso nocapítulodeJDBC.

Basicamente,ocódigoutilizaráoContatoDaoquecriamosanteriormenteparaimprimiralistade

Contato:

<%ContatoDaodao=newContatoDao();List<Contato>contatos=dao.getLista();

for(Contatocontato:contatos){%><li><%=contato.getNome()%>,<%=contato.getEmail()%>:<%=contato.getEndereco()%></li>

<%}%>

Nessecódigoaindafalta,assimcomonoJavapuro,importarasclassesdospacotescorretos.

Parafazermosoimportdasclasses,precisamosdeclararqueaquelapáginaprecisadeacessoàoutrasclassesJava.Paraisso,utilizamosdiretivas,quepossuemaseguintesintaxe:<%@...%>.

Reparequeelaseparecemuitocomscriptlet,comadiferenç[email protected]éumadiretivadepágina,ouseja,umaconfiguraçãoespecíficadeumapágina.

Para isso, utilizamos <%@ page %>. Basta dizermos qual configuração queremos fazer nessa

página,quenonossocasoéimportarumaclasseparautilizá-la:

6.3LISTANDOOSCONTATOSCOMSCRIPTLET

6.3LISTANDOOSCONTATOSCOMSCRIPTLET 85

Page 95: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<%@pageimport="br.com.caelum.agenda.dao.ContatoDao"%>

Oatributoimport permite que seja especificado qual o pacote a ser importado. Para importar

diversospacotes,podemossepará-losporvírgulas(videoexercício).

1. CrieoarquivoWebContent/lista-contatos-scriptlet.jspesiga:

Importeospacotesnecessários.UseoCtrl+EspaçodoEclipseparaajudaraescreverospacotes.

<%@pageimport="java.util.*,br.com.caelum.agenda.dao.*,br.com.caelum.agenda.modelo.*"%>

Coloqueocódigoparafazeralistagem.UsebastanteoCtrl+EspaçodoEclipse.

<html><body><table><%ContatoDaodao=newContatoDao();List<Contato>contatos=dao.getLista();

for(Contatocontato:contatos){%><tr><td><%=contato.getNome()%></td><td><%=contato.getEmail()%></td><td><%=contato.getEndereco()%></td><td><%=contato.getDataNascimento().getTime()%></td></tr><%}%></table></body></html>

Testeaurlhttp://localhost:8080/fj21-agenda/lista-contatos-scriptlet.jsp

1. Repare que a data apareceu de uma forma complicada de ler. Tente mostrá-la formatadautilizandoaclasseSimpleDateFormat.

2. Coloquecabeçalhosparaascolunasdatabela,descrevendooquecadacolunasignifica.3. Tenteutilizaroquadroaseguirparadefinirapáginapadrãodeseusite.

6.4EXERCÍCIOSOPCIONAIS:LISTADECONTATOSCOMSCRIPTLET

86 6.4EXERCÍCIOSOPCIONAIS:LISTADECONTATOSCOMSCRIPTLET

Page 96: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

WELCOME-FILE-LIST

Oarquivoweb.xmlabaixodizqueosarquivoschamados"bemvindo.jsp"devemserchamadosquandoumclientetentaacessarumdiretóriowebqualquer.

Ovalordessecampocostumaser"index.html"emoutraslinguagensdeprogramação.

ComovocêpodeverpeloarquivogeradoautomaticamentepeloWTP,épossívelindicarmaisdeumarquivoparaseroseuwelcome-file!Mude-opara:

<welcome-file-list><welcome-file>bemvindo.jsp</welcome-file></welcome-file-list>

ReinicieotomcateacesseaURL:http://localhost:8080/fj21-agenda/

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

AbrimosocapítulodizendoquenãoqueríamosmisturarcódigoJavacomcódigoHTMLnasnossasServlets,pois,prejudicavaalegibilidadedonossocódigoeafetavaamanutenção.

Maséjustamenteissoqueestamosfazendoagora,sóquenoJSP,atravésdeScriptlets.

ÉcomplicadoficarescrevendoJavaemseuarquivoJSP,nãoé?

Primeiro,ficatudomalescritoedifícildeler.OJavapassaaatrapalharocódigoHTMLemvezdeajudar. Depois, quando o responsável pelo design gráfico da página quiser alterar algo, terá queconhecerJavaparaentenderoqueestáescritoládentro.Hmm...nãopareceumaboasolução.

Seuslivrosdetecnologiaparecemdoséculopassado?

6.5MISTURANDOCÓDIGOJAVACOMHTML

6.5MISTURANDOCÓDIGOJAVACOMHTML 87

Page 97: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

E existe hoje em dia no mercado muitas aplicações feitas inteiramente utilizando scriptlets eescrevendocódigoJavanomeiodosHTMLs.

Comodecorrerdocurso,vamosevoluirnossocódigoatéumpontoemquenãofaremosmaisessamistura.

PararemoverumpoucodocódigoJavaqueficanapáginaJSP,aSundesenvolveuumalinguagemchamadaExpressionLanguagequeéinterpretadapeloservletcontainer.

Nosso primeiro exemplo com essa linguagem é utilizá-la para mostrar parâmetros que o clienteenviaatravésdesuarequisição.

Porexemplo,seoclientechamaapáginatestaparam.jsp?idade=24,oprogramadevemostrara

mensagemqueoclientetem24anos.

Como fazer isso? Simples, existe uma variável chamadaparam que, na expression language, é

responsável pelos parâmetros enviados pelo cliente. Para ler o parâmetro chamado idade basta usar${param.idade}.Paraleroparâmetrochamadodiadevemosusar${param.dia}.

A expression language ainda vai ser utilizada para muitos outros casos, não apenas para pegarparâmetrosquevieramdorequest.ElaéaformamaiselegantehojeemdiaparatrabalharnoJSPeseráexploradanovamenteduranteoscapítulosposteriores.

1. CrieumapáginachamadaWebContent/digita-idade.jspcomoconteúdo:

<html><body>Digitesuaidadeepressioneobotão:<br/>

<formaction="mostra-idade.jsp">Idade:<inputtype="text"name="idade"/><inputtype="submit"/></form></body></html>

1. Crie um arquivo chamado WebContent/mostra-idade.jsp e coloque o código de expressionlanguagequemostraaidadequefoienviadacomoparâmetroparaessapágina:

<html><body>Testandoseusparâmetros:<br/>Aidadeé${param.idade}.</body></html>

6.6EL:EXPRESSIONLANGUAGE

6.7EXERCÍCIOS:PARÂMETROSCOMAEXPRESSIONLANGUAGE

88 6.6EL:EXPRESSIONLANGUAGE

Page 98: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. Testeosistemaacessandoapáginahttp://localhost:8080/fj21-agenda/digita-idade.jsp.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Os arquivos JSPs não são compilados dentro do Eclipse, por esse motivo na hora que estamosescrevendooJSPnoEclipsenãoprecisamosdasclassesdodriver.

Os JSPs são transformados emumaServlet, quevimos anteriormente, porumcompilador JSP (oTomcatcontémumcompiladorembutido).EssecompiladorJSPpodegerarumcódigoJavaqueéentãocompiladoparagerarbytecodediretamenteparaaservlet.

Então,somenteduranteaexecuçãodeumapáginaJSP,quandoeleétransformadoemumaservlet,queseucódigoJavaécompiladoenecessitamosdasclassesdodriverquesãoprocuradasnodiretóriolib.

Agoraéamelhorhoradeaprenderalgonovo

6.8PARASABERMAIS:COMPILANDOOSARQUIVOSJSP

6.8PARASABERMAIS:COMPILANDOOSARQUIVOSJSP 89

Page 99: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO7

"Saberécompreendermosascoisasquemaisnosconvém."--FriedrichNietzsche

Nesse capítulo, você aprenderá o que são Taglibs e JSTL. E também terá a chance de utilizaralgumasdasprincipaistagsdogrupocoreefmt.

Nocapítuloanterior,começamosamelhorarnossosproblemascomrelaçãoàmisturadecódigoJavacomHTMLatravésdaExpressionLanguage.No entanto, ela sozinhanãopodenos ajudarmuito,

poiselanãonospermite,porexemplo,instanciarobjetos,fazerverificaçõescondicionais(ifelse),

iteraçõescomoemumforeassimpordiante.

Paraquepossamosteressecomportamentosemimpactarnalegibilidadedonossocódigo,teremosque escrever esse código nos nossos JSPs numa forma parecida com o que já escrevemos lá, que éHTML,logo,teremosqueescrevercódigobaseadoemTags.

Issomesmo,umatag!ASunpercebeuqueosprogramadoresestavamabusandodocódigoJavanoJSP e tentou criar algo mais "natural" (um ponto um tanto quanto questionável da maneira que foiapresentadanoinício),sugerindoousodetagsparasubstituirtrechosdecódigo.

Oresultadofinaléumconjuntodetags(umataglibrary,outaglib)padrão,quepossui,entreoutrastags,afuncionalidadedeinstanciarobjetosatravésdoconstrutorsemargumentos.

USANDOTAGLIBS

7.1TAGLIBS

90 7USANDOTAGLIBS

Page 100: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

Como já foi comentado anteriormente, os Javabeans devem possuir o construtor público semargumentos(umtípicoPlainOldJavaObject:POJO),gettersesetters.

Instanciá-los na nossa página JSP não é complicado.Basta utilizarmos a tag correspondente paraessafunção,quenonossocasoéa<jsp:useBean>.

Parautilizá-la,bastaindicarmosqualaclassequeremosinstanciarecomosechamaráavariávelqueseráatribuídaessanovainstância.

<jsp:useBeanid="contato"class="br.com.caelum.agenda.modelo.Contato"/>

Podemosimprimironomedocontato(queestáembranco,claro...):

${contato.nome}

Mas,ondeestáogetNome()?Aexpressionlanguageécapazdepercebersozinhaanecessidadede

chamarummétododotipogetter,porissoopadrãogetter/setterdoPOJOétãoimportantehojeemdia.

Desta maneira, classes como Contato são ferramentas poderosas por seguir esse padrão pois

diversasbibliotecasimportantesestãobaseadasnele:Hibernate,Struts,VRaptor,JSF,EJBetc.

ATENÇÃO

NaExpressionLanguage${contato.nome} chamaráométodogetNome por padrão.Para

que isso sempre funcione, devemos colocar o parâmetro em letra minúscula. Ou seja,${contato.Nome}nãofunciona.

EditoraCasadoCódigocomlivrosdeumaformadiferente

7.2INSTANCIANDOPOJOS

7.2INSTANCIANDOPOJOS 91

Page 101: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Seguindo a ideia demelhorar o código Java que precisa de umamaneira ou outra ser escrito napáginaJSP,aSunsugeriuousodaJavaServerPagesStandardTagLibrary,aJSTL.

OBSERVAÇÃO

Antesde2005,JSTLsignificavaJavaServerPagesStandardTemplateLibrary.

AJSTLéaAPIqueencapsulouemtagssimplestodaafuncionalidadequediversaspáginasWebprecisam,comocontroledelaços(fors),controledefluxodotipoifelse,manipulaçãodedados

XMLeainternacionalizaçãodesuaaplicação.

Antigamente,diversasbibliotecasforamcriadasporváriosgruposcomfuncionalidadessimilaresaoJSTL (principalmente aoCore), culminando com a aparição damesma, em uma tentativa da Sun depadronizaralgoqueomercadovêcomoútil.

Existem ainda outras partes da JSTL, por exemplo aquela que acessa banco de dados e permiteescrevercódigosSQLnanossapágina,masseodesignernãocompreendeJavaoquediremosdeSQL?OusodetalpartedaJSTLédesencorajado.

AJSTLfoiaformaencontradadepadronizarotrabalhodemilharesdeprogramadoresdepáginasJSP.

Antesdisso,muitagenteprogramavacomonosexemplosquevimosanteriormente, somentecomJSPseJavabeans,ochamadoModelo1,quenaépocafaziapartedosBlueprintsdeJ2EEdaSun(boaspráticas)enósvamosdiscutirmaisparafrentenocurso.

MuitaspáginasJSPnoBrasilaindapossuemgrandespedaçosdescriptletsespalhadosdentrodelas.

RecomendamosatodososnossosalunosqueoptarempeloJSPcomocamadadevisualização,queutilizemaJSTLeoutrasbibliotecasde tagparaevitarocódigo incompreensívelquepodesergeradocomscriptlets.

Ocódigodasscriptletsmaisconfundedoqueajuda,tornandoamanutençãodapáginaJSPcadavezmaiscustosaparaoprogramadoreparaaempresa.

Para instalar a implementação mais famosa da JSTL basta baixar a mesma no site

7.3JSTL

Asempresashojeemdia

7.4INSTALAÇÃO

92 7.3JSTL

Page 102: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

http://jstl.java.net/.

AousaroJSTLemalgumapáginaprecisamosprimeirodefinirocabeçalho.ExistemquatroAPIsbásicasevamosaprenderprimeiroautilizarabibliotecachamadadecore.

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

SemprequevamosutilizarumataglibdevemosprimeiroescreverumcabeçalhoatravésdeumatagJSPquedefinequaltaglibvamosutilizareumnome,chamadoprefixo.

EsseprefixopodeterqualquervalormasnocasodataglibcoredaJSTLopadrãodaSunéaletrac.Já a URI (que não deve ser decorada) é mostrada a seguir e não implica em uma requisição peloprotocolohttpesimumabuscaentreosarquivos.jarnodiretóriolib.

<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>

UsandoaJSTLcore,vamosreescreveroarquivoquelistatodoscontatos.

Ocabeçalhojáéconhecidodaseçãoanterior:

<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>

Depois, precisamos instanciar e declarar nosso DAO. Ao revisar o exemplo da lista através descriptlets,queremosexecutaroseguinte:

classe:br.com.caelum.jdbc.dao.ContatoDao;

construtor:semargumentos;variável:DAO.

JáconheceoscursosonlineAlura?

7.5CABEÇALHOPARAAJSTLCORE

7.6FOREACH

7.5CABEÇALHOPARAAJSTLCORE 93

Page 103: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Já vimos a tag jsp:useBean, capaz de instanciar determinada classe através do construtor semargumentosedarumnome(id)paraessavariável.

PortantovamosutilizarataguseBeanparainstanciarnossoContatoDao:

<jsp:useBeanid="dao"class="br.com.caelum.agenda.dao.ContatoDao"/>

Comotemosavariáveldao,desejamoschamarométodogetListaepodemosfazerissoatravés

daEL:

${dao.lista}

Desejamosexecutarumloopparacadacontatodentrodacoleçãoretornadaporessemétodo:

arrayoucoleção:dao.lista;variáveltemporária:contato.

Nonossoexemplocomscriptlets,oquefaltaéachamadadométodogetListaeaiteração:

<%//...List<Contato>contatos=dao.getLista();

for(Contatocontato:contatos){%><%=contato.getNome()%>,<%=contato.getEmail()%>,<%=contato.getEndereco()%>,<%=contato.getDataNascimento()%><%}%>

A JSTL core disponibiliza uma tag chamada c:forEach capaz de iterar por uma coleção,

exatamente o que precisamos. No c:forEach, precisamos indicar a coleção na qual vamos iterar,

atravésdoatributoitemsetambémcomochamaráoobjetoqueseráatribuídoparacadaiteraçãono

atributovar.Oexemploaseguirmostraousodeexpressionlanguagedeumamaneiramuitomais

elegante:

<c:forEachvar="contato"items="${dao.lista}">${contato.nome},${contato.email},${contato.endereco},${contato.dataNascimento}</c:forEach>

Maiselegantequeocódigoquefoiapresentadousandoscriptlets,não?

94 7.6FOREACH

Page 104: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

FOREACHEVARSTATUS

ÉpossívelcriarumcontadordotipointdentrodoseulaçoforEach.Paraisso,bastadefinir

oatributochamadovarStatus para avariáveldesejadaeutilizar apropriedadecount dessa

variável.

<tableborder="1"><c:forEachvar="contato"items="${dao.lista}"varStatus="id"><trbgcolor="#${id.count%2==0?'aaee88':'ffffff'}"><td>${id.count}</td><td>${contato.nome}</td></tr></c:forEach></table>

1. PrecisamosprimeirocolocarosJARsdaJSTLemnossaaplicação.

Primeiro,váaoDesktop,eentrenodiretório21/projeto-agenda/jstlHaverádoisjars,jakarta.servlet.jsp.jstl-1.2.x.jarejakarta.servlet.jsp.jstl-api-1.2.x.jarCopie-os (CTRL+C) e cole-os (CTRL+V) dentro de workspace/fj21-agenda/WebContent/WEB-INF/libNoEclipse,dêumF5noseuprojetooucliquecomobotãodireitodomousesobreonomedoprojetoeescolhaaopçãoRefresh.

EMCASA

Casovocêesteja emcasa,pode fazerodownloadda JSTLAPIeda implementaçãoem:https://bit.ly/fj21_jstl_apihttps://bit.ly/fj21_jstl_impl

2. ListeoscontatosdeContatoDaousandojsp:useBeaneJSTL.

Crieoarquivolista-contatos.jsp,dentrodapastaWebContent/ usandoo atalhodenovoJSPnoEclipse;

Antesdeescrevermosnossocódigo,precisamosimportarataglibJSTLCore.Issoéfeitocomadiretiva<%@taglib%> no topo do arquivo.Usando o recurso de autocompletar doEclipse

(inclusivenaURL),declareataglibnotopodoarquivo:

<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>

Localizeatag<body>noarquivoe implementeoconteúdodanossapáginadentrodobody.

7.7EXERCÍCIOS:FOREACH

7.7EXERCÍCIOS:FOREACH 95

Page 105: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

VamosusarumatabelaHTMLeastags<jsp:useBean/>e<c:forEach/>quevimosantes:

<!--criaoDAO--><jsp:useBeanid="dao"class="br.com.caelum.agenda.dao.ContatoDao"/>

<table><!--percorrecontatosmontandoaslinhasdatabela--><c:forEachvar="contato"items="${dao.lista}"><tr><td>${contato.nome}</td><td>${contato.email}</td><td>${contato.endereco}</td><td>${contato.dataNascimento.time}</td></tr></c:forEach></table>

Acessehttp://localhost:8080/fj21-agenda/lista-contatos.jsp

ReparequeapóscriarumanovapáginaJSPnãoprecisamosreiniciaronossocontainer!

3. ScriptletsouJSTL?Qualdosdoisémaisfácilentender?

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

1. Coloqueumcabeçalhonascolunasdatabelacomumtítulodizendoàqueserefereacoluna.2. Utilizeumavariáveldestatusnoseuc:forEachparacolocarduascoresdiferentesemlinhaspares

eímpares.(UtilizecomoauxíliooboximediatamenteantesdoexercíciosobreforEach)

VocêpodetambémfazerocursodatadessaapostilanaCaelum

7.8EXERCÍCIOSOPCIONAIS

96 7.8EXERCÍCIOSOPCIONAIS

Page 106: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Alistagemdosnossoscontatosfuncionaperfeitamente,masonossoclienteaindanãoestásatisfeito.Elequerumpoucomaisdefacilidadenessatela,esugerequecasoousuáriotenhae-mailcadastrado,coloquemosumlinknoe-mailquequandoclicadoabraosoftwaredee-maildocomputadordousuárioparaenviarumnovoe-mailparaesseusuário.Comopodemosfazeressafuncionalidade?

Vamosanalisaroproblemacomcalma.Primeiro,percebemosquevamosprecisarcriarumlinkparaenvio de e-mail. Isso é facilmente conseguido através da tag do HTML <a> com o parâmetro

href="mailto:[email protected]".Primeiroproblemaresolvidofacilmente,masagoratemosoutro.

Comofaremosaverificaçãoseoe-mailestáounãopreenchido?

Paraquepossamosfazeressaverificaçãoprecisaremosfazerumifparasabermosseoe-mailestá

preenchido ou não. Mas, novamente, não queremos colocar código Java na nossa página e jáaprendemosqueestamosmudandoissoparautilizar tags.Paraessafinalidade,existeatagc:if, na

qualpodemosindicarqualotestelógicodeveserfeitoatravésdoatributotest.Essetesteéinformado

atravésdeExpressionLanguage.

Paraverificarmosseoe-mailestápreenchidoounão,podemosfazeroseguinte:

<c:iftest="${notemptycontato.email}"><ahref="mailto:${contato.email}">${contato.email}</a></c:if>

Podemos também, caso o e-mail não tenha sido preenchido, colocar a mensagem "e-mail nãoinformado",aoinvésdenossatabelaficarcomumespaçoembranco.Reparequeesseéjustamenteocasocontrárioquefizemosnonossoif,logo,éequivalenteaoelse.

OproblemaéquenãotemosatagelsenaJSTL,porquestõesestruturaisdeXML.Umaprimeira

alternativa seria fazermosoutro<c:if> coma lógica invertida.Mas issonão é uma soluçãomuito

elegante. No Java, temos outra estrutura condicional que consegue simular um if/else, que é o

switch/case.

Parasimularmosswitch/casecomJSTL,utilizamosatagc:chooseeparacadacasodoswitch

fazemosc:when.Odefaultdoswitchpodeserrepresentadoatravésdatagc:otherwise,comono

exemploaseguir:

<c:choose><c:whentest="${notemptycontato.email}"><ahref="mailto:${contato.email}">${contato.email}</a></c:when><c:otherwise>E-mailnãoinformado</c:otherwise>

7.9EVOLUINDONOSSALISTAGEM

7.10FAZENDOIFSCOMAJSTL

7.9EVOLUINDONOSSALISTAGEM 97

Page 107: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

</c:choose>

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

1. Vamoscolocaremnossalistagemumlinkparaenviodee-mailcasoomesmotenhasidoinformado.

Abraoarquivolista-contatos.jspnoEclipse;

Nomomentode imprimiroe-maildocontato, adicioneumaverificaçãopara saber seoe-mailestápreenchidoe,casoesteja,adicioneumlinkparaenviodee-mail:

<c:forEachvar="contato"items="${dao.lista}"><tr><td>${contato.nome}</td><td><c:iftest="${notemptycontato.email}"><ahref="mailto:${contato.email}">${contato.email}</a></c:if></td><td>${contato.endereco}</td><td>${contato.dataNascimento.time}</td></tr></c:forEach>

Acesseapáginanonavegadorpeloendereçohttp://localhost:8080/fj21-agenda/lista-contatos.jsp

1. Vamoscolocaramensagem"E-mailnãoinformado"casooe-mailnãotenhasidoinformado

Seuslivrosdetecnologiaparecemdoséculopassado?

7.11EXERCÍCIOS:LISTADECONTATOSCOMCONDICIONAIS

98 7.11EXERCÍCIOS:LISTADECONTATOSCOMCONDICIONAIS

Page 108: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Abaixodonovoifquefizemosnoitemanterior,vamoscolocarmaisumif,dessavezcoma

verificaçãocontrária,ouseja,queremossaberseestávazio:

<c:forEachvar="contato"items="${dao.lista}"><tr><td>${contato.nome}</td><td><c:iftest="${notemptycontato.email}"><ahref="mailto:${contato.email}">${contato.email}</a></c:if>

<c:iftest="${emptycontato.email}">E-mailnãoinformado</c:if></td><td>${contato.endereco}</td><td>${contato.dataNascimento.time}</td></tr></c:forEach>

Casovocênãopossuanenhumcontatoseme-mail,cadastrealgum.

Acessealista-contatos.jsppelonavegadorevejaoresultadofinal.

1. (Opcional)Aoinvésdeutilizardoisifs,useatagc:choose

UmrequisitocomumquetemosnasaplicaçõesWebhojeemdiaécolocarcabeçalhoserodapénaspáginasdonossosistema.Essescabeçalhoserodapéspodemterinformaçõesdaempresa,dosistemaeassimpordiante.Oproblemaéque,nagrandemaioriadasvezes,todasaspáginasdanossaaplicaçãoprecisamteressemesmocabeçalhoerodapé.Comopoderíamosresolverisso?

Uma primeira alternativa e talvez a mais inocente é colocarmos essas informações em todas aspáginasdanossaaplicação,copiandoecolandotodoocabeçalhováriasvezes.

Masoqueaconteceriaseprecisássemosmudarologotipodaempresa?Teríamosquemudartodasaspáginas,oquenãoéumtrabalhoagradável.

Umaalternativamelhorseriaisolarmosessecódigoqueserepeteemtodasaspáginasemumaoutra

7.12IMPORTANDOPÁGINAS

7.12IMPORTANDOPÁGINAS 99

Page 109: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

página, por exemplo, cabecalho.jsp e todas as páginas da nossa aplicação, apenas dizem que

precisamdessaoutrapáginanela,atravésdeumatagnova,ac:import.

Para utilizá-la, podemos criar uma pagina com o cabeçalho do sistema, por exemplo, acabecalho.jsp:

<imgsrc="imagens/logomarca.jpg"/>Nomedaempresa

Eumapáginaparaorodapé,porexemplo,rodape.jsp:

Copyright2010-Todososdireitosreservados

Bastariaque, em todasasnossaspáginas,porexemplo,nalista-contatos.jsp, colocássemos

ambasaspáginas,atravésdac:importcomoabaixo:

<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><html><body>

<c:importurl="cabecalho.jsp"/>

<jsp:useBeanid="dao"class="br.com.caelum.agenda.dao.ContatoDao"/><table><!--for--><c:forEachvar="contato"items="${dao.lista}"><tr><td>${contato.nome}</td><td>${contato.email}</td><td>${contato.endereco}</td><td>${contato.dataNascimento.time}</td></tr></c:forEach></table>

<c:importurl="rodape.jsp"/>

</body></html>

1. Vamosprimeirocriaronossocabeçalho,utilizandoologotipodaCaelum.

Vá noDesktop, entre na pasta21/projeto-agenda e copie o diretório imagens para dentro dodiretórioWebContentdoseuprojeto.EssediretóriopossuiologotipodaCaelum.

CriedentrodeWebContentumarquivochamadocabecalho.jspcomologotipodosistema:

<imgsrc="imagens/caelum.png"style="width:40%;"/><h2>AgendadeContatosdo(a)(Seunomeaqui)</h2><hr/>

Vocêpodeajustar a largurada imagemalterandoaporcentagemnoestilo cssstyle="width:

7.13EXERCÍCIOS:CABEÇALHOSERODAPÉS

100 7.13EXERCÍCIOS:CABEÇALHOSERODAPÉS

Page 110: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

40%;"

Crietambémapáginarodape.jsp:

<hr/>Copyright2020-Todososdireitosreservados

Podemosimportarasduaspáginas(cabecalho.jsperodape.jsp), dentrodanossalista-

contatos.jspusandoatagc:importquevimos:

<html><body><%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>

<c:importurl="cabecalho.jsp"/>

<!--criaalista--><jsp:useBeanid="dao"class="br.com.caelum.agenda.dao.ContatoDao"/><table><!--for--><c:forEachvar="contato"items="${dao.lista}"><tr><td>${contato.nome}</td>

<td><c:iftest="${notemptycontato.email}"><ahref="mailto:${contato.email}">${contato.email}</a></c:if><c:iftest="${emptycontato.email}">E-mailnãoinformado</c:if></td>

<td>${contato.endereco}</td><td>${contato.dataNascimento.time}</td></tr></c:forEach></table>

<c:importurl="rodape.jsp"/></body></html>

Visualize o resultado final acessando no navegador http://localhost:8080/fj21-

agenda/lista-contatos.jsp

7.13EXERCÍCIOS:CABEÇALHOSERODAPÉS 101

Page 111: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Apesar da nossa listagem de contatos estar bonita e funcional, ela ainda possui problemas, porexemplo, a visualização da data de nascimento.Muitas informações aparecem na data, como horas,minutosesegundos,coisasquenãoprecisamos.

Jáaprendemosanteriormentequeumadas formasquepodemos fazer essa formataçãoemcódigoJava é através da classeSimpleDateFormat,mas não queremos utilizá-la aqui, pois não queremos

códigoJavanonossoJSP.

Paraisso,vamosutilizaroutraTaglibdaJSTLqueéataglibdeformatação,afmt.

Para utilizarmos a taglib fmt, precisamos importá-la, damesma forma que fizemos com a tag

core,atravésdadiretivadetaglib,comoabaixo:

<%@tagliburi="http://java.sun.com/jsp/jstl/fmt"prefix="fmt"%>

Dentro da taglib fmt, uma das tags que ela possui é a formatDate, que faz com que um

determinadoobjetodotipojava.util.Datesejaformatadoparaumdadopattern.Então,podemos

utilizaratagfmt:formatDatedaseguinteforma:

<fmt:formatDatevalue="${contato.dataNascimento.time}"pattern="dd/MM/yyyy"/>

Repare que, naExpressionLanguage que colocamos no value, há no final um .time. Isso

porqueoatributovaluesóaceitaobjetosdotipojava.util.Date,enossadatadenascimentoéum

java.util.Calendar que possui um método getTime() para chegarmos ao seu respectivo

java.util.Date.

Agoraéamelhorhoradeaprenderalgonovo

7.14FORMATAÇÃODEDATAS

102 7.14FORMATAÇÃODEDATAS

Page 112: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

COMOFAZERPATTERNSMAISCOMPLICADOS?

Podemos no atributo pattern colocar outras informações com relação ao objeto

java.util.Datequequeremosmostrar,porexemplo:

m-Minutos

s-Segundos

H-Horas(0-23)

D-Dianoano,porexemplo,230

Sugerimosquequandoprecisardeformataçõesmaiscomplexas,leiaadocumentaçãodaclasseSimpleDateFormat,aondeseencontraadescriçãodealgunscaracteresdeformatação.

1. Vamosfazeraformataçãodadatadenascimentodosnossoscontatos.

Nalista-contatos.jsp, importea taglibfmtno topodoarquivo.Useoautocompletardo

Eclipseparateajudaraescrever:

<%@tagliburi="http://java.sun.com/jsp/jstl/fmt"prefix="fmt"%>

TroqueaExpressionLanguagequemostraadatadenascimentoparapassarpelatagformatDate

abaixo:

<fmt:formatDatevalue="${contato.dataNascimento.time}"pattern="dd/MM/yyyy"/>

Acesseapáginapelonavegadorevejaoresultadofinal:

7.15 EXERCÍCIOS: FORMATANDO A DATA DE NASCIMENTO DOSCONTATOS

7.15EXERCÍCIOS:FORMATANDOADATADENASCIMENTODOSCONTATOS 103

Page 113: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Muitas vezes trabalhar com links em nossa aplicação é complicado. Por exemplo, no arquivocabecalho.jspincluímosumaimagemchamadacaelum.pngqueestánapastaimagens.

IncluímosestaimagemcomatagHTML<img>utilizandoocaminhoimagens/caelum.pngqueéumcaminhorelativo,ouseja,seocabecalho.jspestivernaraizdoprojeto,oarquivocaelum.png

deveráestaremumapastachamadaimagenstambémnaraizdoprojeto.

Utilizar caminhos relativos muitas vezes é perigoso. Por exemplo, se colocarmos o arquivocabecalho.jsp emumdiretóriochamadoarquivos_comuns, a imagemque tínhamos adicionado

seráprocuradaemumdiretórioimagensdentrododiretórioarquivos_comuns.Resultado,aimagem

nãoseráexibida.

Poderíamos resolver isso utilizando um caminho absoluto. Ao invés de adicionarmos a imagemutilizando o caminho imagens/caelum.png , poderíamos usar /imagens/caelum.png . Só que

utilizandoa/elenãovaiparaaraizdaminhaaplicaçãoesimparaaraizdotomcat,ouseja,eleiria

procuraraimagemcaelum.pngemumdiretórioimagensna raizdo tomcat,quandonaverdadeo

diretórionemmesmoexiste.

Poderíamos resolver isso utilizando o caminho /fj21-tarefas/imagens/caelum.png . Nosso

problemaseriaresolvido,entretanto,sealgumdiamudássemosocontextodaaplicaçãoparatarefasa

imagemnãoseriaencontrada,poisdeixamosfixononossojspqualeraocontextodaaplicação.

Pararesolveresteproblema,podemosutilizaratag<c:url>daJSTL.Ousodelaéextremamente

simples.Paraadicionarmosologotipodacaelumnocabecalho.jsp,faríamosdaseguintemaneira:

<c:urlvalue="/imagens/caelum.png"var="imagem"/><imgsrc="${imagem}"/>

Oudeumaformaaindamaissimples:

<imgsrc="<c:urlvalue="/imagens/caelum.png"/>"/>

OHTMLgeradopeloexemploseria:<imgsrc="fj21-tarefas/imagens/caelum.png"/>.

7.16PARASABERMAIS:LINKSCOM<C:URL>

104 7.16PARASABERMAIS:LINKSCOM

Page 114: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

1. Vamossubstituirocaminhorelativopeloabsoluto.Abraoarquivocabecalho.jspealtere-oadicionandoatag<c:url>:

<imgsrc="<c:urlvalue="/imagens/caelum.png"/>"style="width:40%;"/>

Como vamos usar a JSTL também nesse novo arquivo de cabeçalho, não deixe de incluir adeclaraçãodataglibnoiníciodoarquivo.(ocomando<%@taglib...%>semelhanteaousadona

listagem)

Visualize o resultado acessando no navegador http://localhost:8080/fj21-agenda/lista-contatos.jsp

Aimagemcaelum.pngcontinuaaparecendonormalmente

Se,algumdia,alterarmosocontextodanossaaplicação,ocabeçalhocontinuariaexibindoaimagemdamaneiracorreta.Usandoatag<c:url>ficamoslivresparautilizarcaminhosabsolutos.

AJSTLpossuialémdastagsquevimosaqui,muitasoutras,eparadiversasfinalidades.AbaixoestáumresumocomalgumasdasoutrastagsdaJSTL:

c:catch-blocodotipotry/catchc:forTokens-foremtokens(ex:"a,b,c"separadosporvírgula)c:out-saídac:param-parâmetroc:redirect-redirecionamento

EditoraCasadoCódigocomlivrosdeumaformadiferente

7.17EXERCÍCIOSOPCIONAIS:CAMINHOABSOLUTO

7.18PARASABERMAIS:OUTRASTAGS

7.17EXERCÍCIOSOPCIONAIS:CAMINHOABSOLUTO 105

Page 115: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

c:remove-remoçãodevariávelc:set-criaçãodevariável

Leia detalhes sobre as taglibs da JSTL (JavaDoc das tags e classes) em:https://jakarta.ee/specifications/tags/1.2/tagdocs/

106 7.18PARASABERMAIS:OUTRASTAGS

Page 116: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO8

"Euapenasinventoeesperoqueoutrosapareçamprecisandodoqueinventei"--R.BuckminsterFuller

Aotérminodessecapítulo,vocêserácapazde:

criarsuaprópriataglibatravésdetagfiles;encapsularcódigosrepetitivosemtags;conheceroutrastaglibsexistentesnomercado.

Émuitocomum,nomomentoemqueestamosdesenvolvendonossosJSPs,cairmosemsituaçõesemquefazemosmuitarepetiçãodecódigo.Porexemplo,semprequecriamosumacaixadetexto,podemosassociá-lacomumlabel,atravésdoseguintecódigo:

<labelfor="nomeContato">Nome</label><inputtype="text"id="nomeContato"name="nome"/>

Essecódigofazcomque,sevocêclicarnapalavraNome,passeofocoparaocampodetexto.Masreparequetemosalgoqueserepetenessetrecho,queéoiddoinputeoatributofordolabel.

Semudarmosoiddoinputteremosquerefletiressaalteraçãonofordolabel.Alémdisso,temos

quesempreescrevertodoessecódigo.

Não seria mais simples escrevermos <campoTexto id="nomeContato" name="nome"

label="Nome:"/>etodoaquelecódigosergeradoparanós?

UmoutroexemplopoderiaserquandoutilizamoscomponentesquedependemdeJavascript,comoumcampoque,aoganharofoco,mostraumcalendário.Todavezquetemosqueusaressecomponente,precisamosescreverumpedaçodecódigoJavaScript.Porquenãoencapsulartudoissoemnovastags

TAGSCUSTOMIZADASCOMTAGFILES

8.1PORQUEEUPRECISARIADEOUTRASTAGSALÉMDAJSTL?

8TAGSCUSTOMIZADASCOMTAGFILES 107

Page 117: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

customizadas?

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

VamospegarumexemplopráticodepossívelusodeJavaScriptnonossosistema.Temosnocadastrodecontatos,umcampoparadatadenascimento.Masatéomomento,ousuárioprecisadigitaradatanamãoseguindooformatoqueespecificamos.

EsemostrássemosumcalendárioemJavaScriptparaousuárioescolheradataapenasclicandoemumcomponentejápronto?

Paraconseguirmosessecomportamento,podemosutilizarporexemplooscomponentesvisuaisdojQuery,queéumabibliotecacomalgunscomponentesJavaScript.

EntreosdiversoscomponentesqueojQuerypossui,umdeleséocampocomcalendário,tambémconhecidopordatepicker. Para utilizarmosodatepicker do jQuery, precisamos criar uminput de

textosimpleseassociá-locomumafunçãoJavaScript,comonocódigoseguinte:

<inputid="dataNascimento"type="text">

<script>$("#dataNascimento").datepicker();</script>

AfunçãoJavaScriptfazcomqueoinputcujoidédataNascimentosejaumcalendário.

Imagine se toda hora que fossemos criar um campode data tivéssemos que escrever esse códigoJavaScript?Aschancesdeerrarmosessecódigoérazoável,masaindaassim,opiorpontoaindaseriaperdertempoescrevendoumcódigorepetitivo,sendoquepoderíamosobteromesmoresultadoapenasescrevendo:

<campoDataid="dataNascimento"/>

JáconheceoscursosonlineAlura?

8.2CALENDÁRIOSCOMJQUERY

108 8.2CALENDÁRIOSCOMJQUERY

Page 118: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Qualabordagemémaissimples?

Paraquepossamosteratag<campoData>precisaremoscriá-la.Umadasformasquetemosdecriar

nossasprópriastaglibsécriandoumarquivocontendoocódigoquenossaTaglibgerará.Essesarquivoscontendoocódigodastagssãoconhecidoscomotagfiles.

Tagfiles nadamais são do que pedaços de JSP, com a extensão .tag, contendo o código que

queremosqueanossataggere.

VamoscriarumarquivochamadocampoData.tagcomocódigoquequeremosgerar.

<inputid="dataNascimento"name="dataNascimento">

<script>$("#dataNascimento").datepicker();</script>

Mas essa nossa tag está totalmente inflexível, pois o id e o nome do campo estão escritos

diretamente dentro da tag. O que aconteceria se tivéssemos dois calendários dentro do mesmoformulário?Ambosteriamomesmoname.

Precisamosfazercomqueanossatagrecebaparâmetros.Podemosfazerissoadicionandoadiretiva<%@attribute%> na nossa tag, comosparâmetrosname representandoonomedo atributo e o

parâmetrorequiredcomosvalorestrueoufalse,indicandoseoparâmetroéobrigatórioounão.

<%@attributename="id"required="true"%>

Reparecomoésimples.Bastadeclararessadiretivadeatributonocomeçodonossotagfileetemosa capacidade de receber um valor quando formos usar a tag. Imagine usar essa tag nova no nossoformulário:

<campoDataid="dataNascimento"/>

Já que nossa tag sabe receber parâmetros, basta usarmos esse parâmetro nos lugares adequadosatravésdeexpressionlanguage,comonocódigoabaixo:

<%@attributename="id"required="true"%>

<inputid="${id}"name="${id}"type="text"><script>$("#${id}").datepicker();</script>

Parausarnossatag,assimcomonasoutrastaglibs,precisamosimportarnossostagfiles.Comonãoestamos falandode taglibscomplexascomoaJSTL,massimdepequenosarquivosde tagsdonossopróprioprojeto,vamosreferenciardiretamenteapastaondenossosarquivos.tagestãosalvos.

8.3CRIANDOMINHASPRÓPRIASTAGSCOMTAGFILES

8.3CRIANDOMINHASPRÓPRIASTAGSCOMTAGFILES 109

Page 119: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Nossos tagfilesdevemficarnapastaWEB-INF/tags/dentrodoprojetoe,nomomentodeusarastags,vamosimportarcomamesmadiretiva<%@taglib%>queusamosantes.Adiferençaéque,além

dereceberoprefixodanovataglib,indicamosapastaWEB-INF/tags/comolocalizaçãodastags:

<%@taglibtagdir="/WEB-INF/tags"prefix="caelum"%>

Aqui decidimos importar a nova taglib sob o prefixo caelum, mas poderia ser qualquer nome.Assim,podemosusaratagcomo:

<caelum:campoDataid="dataNascimento"/>

Repare que o nome da nossa nova Tag, é o mesmo nome do arquivo que criamos, ou seja,campoData.tagseráutilizandocomo<caelum:campoData>.

UTILIZANDOBIBLIOTECASJAVASCRIPT

Para podermos utilizar bibliotecas Javascript em nossa aplicação precisamos importar oarquivo.jsquecontémabiblioteca.

Para fazermos essa importação, basta que no cabeçalho da página que queremos utilizar oJavascript,ouseja,naTaghead,declaremososeguinte:

<head><scriptsrc="js/arquivo.js"></script></head>

ParasabermaissobreJavaScript,temososcursosdeWebdaCaelum:

http://www.caelum.com.br/cursos-web-front-end/

110 8.3CRIANDOMINHASPRÓPRIASTAGSCOMTAGFILES

Page 120: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

UTILIZANDOESTILOSEMCSS

Para que possamos construir uma interface agradável para o usuário, na maioria das vezessomenteHTMLnãoésuficiente.

Podemos também utilizar CSS (Cascading Stylesheet), que nada mais é que um arquivocontendo as definições visuais para sua página. Esses arquivos são distribuídos com a extensão.csseparaquepossamosusá-los,precisamostambémimportá-losdentrodatagheaddanossa

páginaquevaiutilizaressesestilos.Comoabaixo:

<head><linkhref="css/meuArquivo.css"rel="stylesheet"></head>

A Caelum oferece os treinamentosWD-43 eWD-47 para quem quer dominar as melhorestécnicas de desenvolvimentoWeb com semântica perfeita, estilos CSS poderosos e JavaScriptscorretosefuncionais.

http://www.caelum.com.br/cursos-web-front-end/

1. Vamos criar nossa tag para o campo de calendário com datepicker. Para isso vamos utilizar abibliotecajavascriptjQuery.

VáaoDesktop,eentrenapasta21/projeto-agenda/;

Copieosdiretóriosjsecssecole-osdentrodeWebContentnoseuprojeto;

EMCASA

Sevocêestiverfazendodecasa,podeacharessesdoisarquivosnopacotedoJQueryUIem:http://jqueryui.com/download

2. QueremosusarJSTLnapáginadeadicionarcontatos,aadiciona-contato.html.Mastemosum

problema. Não podemos utilizar as tags ou expression language em uma página HTML . Para

resolvermosisso,vamostrocarsuaextensãopara.jsp

Clique como botão direito em cima do arquivoadiciona-contato.html e escolha a opção

8.4 EXERCÍCIOS: CRIANDO NOSSA PRÓPRIA TAG PARACALENDÁRIO

8.4EXERCÍCIOS:CRIANDONOSSAPRÓPRIATAGPARACALENDÁRIO 111

Page 121: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Renameetroqueaextensãodehtmlparajsp,dessaformaoarquivosechamaráadiciona-

contato.jsp.

3. Tambémvamosimportarocabeçalhoeorodapénessapágina,portanto,vamosusarotaglibJSTLcore.

Adicionenotopodapágina:

<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>

Vamosimportarocabeçalho,depoisdatag<body>adicione:

<c:importurl="cabecalho.jsp"/>

Faltaorodapé.Antesdefecharotagbody(</body>)adicione:

<c:importurl="rodape.jsp"/>

Cuidadoparanãoapagaroformulário,precisaremosdelemaisparafrente.

Acesse http://localhost:8080/fj21-agenda/adiciona-contato.jsp e verifique o resultado com ocabeçalhoerodapé.

4. PrecisamosimportarojQuerynapáginaadiciona-contato.jsp.Paraissoadicionedepoisdatag

<html>eantesdatag<body>,osestilosCSSeosJavascripts

<html><head><linkhref="css/jquery.css"rel="stylesheet"><scriptsrc="js/jquery.js"></script><scriptsrc="js/jquery-ui.js"></script></head>

112 8.4EXERCÍCIOS:CRIANDONOSSAPRÓPRIATAGPARACALENDÁRIO

Page 122: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<body>

<!--Restantedapáginaaqui-->

1. Vamoscriaranossatagparaocalendário.

DentrodeWEB-INFcrieumdiretóriochamadotags.

CrieumarquivochamadocampoData.tagdentrodeWEB-INF/tags/:

<%@attributename="id"required="true"%>

<inputtype="text"id="${id}"name="${id}"/><script>$("#${id}").datepicker({dateFormat:'dd/mm/yy'});</script>

Parautilizá-la,vamosvoltarparaoadiciona-contato.jspejuntoàdeclaraçãodaTaglibcore,

vamosimportarnossanovatag:

<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><%@taglibtagdir="/WEB-INF/tags"prefix="caelum"%>

Bastatrocarmosoinputdadatadenascimentopelanossanovatag:

<formaction="adicionaContato">Nome:<inputtype="text"name="nome"/><br/>E-mail:<inputtype="text"name="email"/><br/>Endereço:<inputtype="text"name="endereco"/><br/>DataNascimento:<caelum:campoDataid="dataNascimento"/><br/>

<inputtype="submit"value="Gravar"/></form>

Recarregue a página adiciona-contato.jsp e clique no campo da data de nascimento. O

calendáriodeveseraberto,escolhaumadataefaçaagravaçãodocontato.

8.4EXERCÍCIOS:CRIANDONOSSAPRÓPRIATAGPARACALENDÁRIO 113

Page 123: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Verifiqueocódigofontegerado,ereparequeoJavascriptdocalendárioeoinputforamgeradosparanósatravésdenossaTaglib.

1. (opcional)ConsulteadocumentaçãodocomponentedatepickerdojQueryUIparavermaisopções.Vocêpodeacessá-laem:http://jqueryui.com/demos/datepicker/

Consulte,porexemplo,asopçõeschangeYearechangeMonthparamostrarmenusmaisfáceis

paraescolheroanoeomês.Hámuitasoutrasopçõestambém.

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

VocêpodetambémfazerocursodatadessaapostilanaCaelum

8.5PARASABERMAIS:OUTRASTAGLIBSNOMERCADO

114 8.5PARASABERMAIS:OUTRASTAGLIBSNOMERCADO

Page 124: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Muitosdosproblemasdodiaadiaquenóspassamos,alguémjápassouantes,portanto,muitasdasvezes, pode acontecer de já existir uma Taglib que resolva omesmo problema que você pode estarpassando.Portanto, recomendamosque antes de criar a suaTaglib, sempreverifique se já não existealgumaqueresolvaseuproblema.

OmercadoatualmentepossuiváriasTaglibsdisponíveis,eparadiversasfunções,algumasdasmaisconhecidassão:

Displaytag: É uma Taglib para geração fácil de tabelas, e pode ser encontrada emhttp://displaytag.sf.net

Cewolf:ÉumaTaglibparageraçãodegráficosnassuaspáginasetambémpodeserencontradaem:http://cewolf.sourceforge.net/new/

Waffle Taglib: Tags para auxiliar na criação de formulários HTML que é encontrada em:http://waffle.codehaus.org/taglib.html

1. Adicioneadisplaytagnoseuprojetoparafazeralistagemdoscontatos.

8.6DESAFIO:COLOCANDODISPLAYTAGNOPROJETO

8.6DESAFIO:COLOCANDODISPLAYTAGNOPROJETO 115

Page 125: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO9

"Ensinaréaprenderduasvezes."--JosephJoubert

Nessecapítulo,vocêaprenderá:

OpadrãoarquiteturalMVC;AconstruirumframeworkMVCsimples.

ColocartodoHTMLdentrodeumaServletrealmentenãonospareceamelhorideia.Oqueacontecequando precisamosmudar o design da página?O designer não vai saber Java para editar a Servlet,recompilá-laecolocá-lanoservidor.

ImagineusarapenasJSP.Ficaríamoscommuitoscriptlet,queémuitodifícildedarmanutenção.

Umaideiamaisinteressanteéusaroqueébomdecadaumdosdois.

OJSPfoifeitoapenasparaapresentaroresultado,eelenãodeveriafazeracessosabancodedadosenemfazerainstanciaçãodeobjetos.IssodeveriaestaremcódigoJava,naServlet.

O ideal então é que a Servlet faça o trabalho árduo, a tal da lógicadenegócio. E o JSP apenasapresente visualmente os resultados gerados pela Servlet. A Servlet ficaria então com a lógica denegócios(ouregrasdenegócio)eoJSPtemalógicadeapresentação.

ImagineocódigodométododaservletAdicionaContatoServletquefizemosantes:

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse){

//logSystem.out.println("Tentandocriarumnovocontato...");

//acessaobeanContatocontato=newContato();//chamaossetters...

//adicionaaobancodedadosContatoDaodao=newContatoDao();dao.adiciona(contato);

MVC-MODELVIEWCONTROLLER

9.1SERVLETOUJSP?

116 9MVC-MODELVIEWCONTROLLER

Page 126: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

//ok....visualizaçãoout.println("<html>");out.println("<body>");out.println("Contato"+contato.getNome()+"adicionadocomsucesso");out.println("</body>");out.println("</html>");

}

Repare que, no final do nossométodo,misturamos o códigoHTML com Java. O que queremosextrairdocódigoacimaéjustamenteessasúltimaslinhas.

Seriamuitomais interessanteparaoprogramador eparaodesigner terumarquivo JSPchamadocontato-adicionado.jspapenascomoHTML:

<html><body>Contato${param.nome}adicionadocomsucesso</body></html>

Buscamosumaformaderedirecionarasrequisições,capazdeencaminharessarequisiçãoparaumoutrorecursodoservidor:porexemploindodeumaservletparaumJSP.

Paraisso,fazemosodispatchdasrequisições,paraqueoJSPsósejarenderizadodepoisquesuasregrasdenegócio,dentrodeumaservletporexemplo,foramexecutadas.

9.1SERVLETOUJSP? 117

Page 127: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

PoderíamosmelhoraranossaaplicaçãosetrabalhássemoscomocódigoJavanaservleteoHTMLapenasnoJSP.

A API de Servlets nos permite fazer tal redirecionamento. Basta conhecermos a URL que

queremosacessarepodemosusarumobjetoRequestDispatcherparaacessaroutrorecursoWeb,seja

esserecursoumapáginaJSPouumaservlet:

RequestDispatcherrd=request.getRequestDispatcher("/contato-adicionado.jsp");rd.forward(request,response);

PodemosfacilmenteexecutaralógicadenossaaplicaçãoWebemumaservleteentãoredirecionarparaumapáginaJSP,ondevocêpossuiseucódigoHTMLetagsqueirãomanipularosdadostrazidospelaservlet.

FORWARDEINCLUDE

Ométodo forward só pode ser chamado quando nada foi ainda escrito para a saída. No

momentoquealgoforescrito,ficaimpossívelredirecionarousuário,poisoprotocoloHTTPnãopossuimeiosdevoltaratrásnaquiloquejáfoienviadoaocliente.

ExisteoutrométododaclasseRequestDispatcherquerepresentaainclusãodepáginaenão

oredirecionamento.Essemétodosechamaincludeepodeserchamadoaqualquerinstantepara

acrescentaraoresultadodeumapáginaosdadosdeoutra.

Seuslivrosdetecnologiaparecemdoséculopassado?

9.2REQUESTDISPATCHER

118 9.2REQUESTDISPATCHER

Page 128: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Vamos evoluir nossa adição de contatos antes puramente usando Servlets para usar oRequestDispatcher.

1. Seguindo a separação aprendida nesse capítulo, queremos deixar em um JSP separado aresponsabilidadedemontaroHTMLaserdevolvidoparaousuário.

Crieentãoumnovoarquivocontato-adicionado.jspnapastaWebContent:

<html><body>Contato${param.nome}adicionadocomsucesso</body></html>

2. AlteresuaservletAdicionaContatoServletparaque,apósaexecuçãodalógicadenegócios,ofluxodarequisiçãosejaredirecionadoparanossonovoJSP.

Remova no fim da classe o código quemonta a saídaHTML (as chamadas deout.println).

VamossubstituirporumachamadaaoRequestDispatchereexibiromesmoresultadousandoo

JSPquecriamos.Achamadaficanofinaldenossaservlet:

RequestDispatcherrd=request.getRequestDispatcher("/contato-adicionado.jsp");rd.forward(request,response);

1. TesteaURL:http://localhost:8080/fj21-agenda/adiciona-contato.jsp

9.3EXERCÍCIOS:REQUESTDISPATCHER

Resultado

9.3EXERCÍCIOS:REQUESTDISPATCHER 119

Page 129: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Percebaquejáatingimosumresultadoquenãoerapossívelanteriormente.

MuitosprojetosantigosqueforamescritosemJavautilizavamsomenteJSPouservletseoresultadoera assustador: diferentes linguagens misturadas num único arquivo, tornando difícil a tarefa demanutenção do código.Como conteúdomostrado até essemomento, é possível escrever um códigocommuitomaisqualidade:cadatecnologiacomasuaresponsabilidade.

Aquitemosváriasservletsacessandoobancodedados,trabalhandocomosDAOsepedindoparaque o JSP apresente esses dados, o diagrama a seguir mostra a representação doAdicionaContatoServletapósamodificaçãodoexercícioanterior.

Temos o problema de ter muitas servlets. Para cada lógica de negócios, teríamos uma servletdiferente,quesignificaváriasportasdeentradas,algoabominávelemumprojetodeverdade.Imaginedezclassesdemodelo,cincológicasdiferentes,issototalizacinquentaformasdiferentesdeacesso.

EsequiséssemosfazerumLogdaschamadasdessaslógicas?TeríamosqueespalharocódigoparaesseLogportodanossaaplicação.

Sabemosdaexistênciadeferramentasparagerartalcódigoautomaticamente,masissonãoresolveoproblemadacomplexidadedeadministrartantasservlets.

Utilizaremosumaideiaquediminuirábastanteonúmerodeportasdeentradasemnossaaplicação:colocar tudoemumaServlet só e,deacordocomosparâmetrosqueoclienteusar,decidimosoqueexecutar.TeríamosaíumaServletparacontrolaressaparte,comooesboçoabaixo:

//TodasaslógicasdentrodeumaServlet@WebServlet("/sistema")publicclassSistemaTodoServletextendsHttpServlet{

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse){

Stringacao=request.getParameter("logica");

9.4MELHORANDOOPROCESSO

120 9.4MELHORANDOOPROCESSO

Page 130: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

ContatoDaodao=newContatoDao();

if(acao.equals("AdicionaContato")){Contatocontato=newContato();contato.setNome(request.getParameter("nome"));contato.setEndereco(request.getParameter("endereco"));contato.setEmail(request.getParameter("email"));dao.adiciona(contato);

RequestDispatcherrd=request.getRequestDispatcher("/contato-adicionado.jsp");rd.forward(request,response);}elseif(acao.equals("ListaContatos")){//buscaalistanoDAO//despachaparaumjsp}elseif(acao.equals("RemoveContato")){//fazaremoçãoeredirecionaparaalista}}}

Poderíamos acessar no navegador algo como http://localhost:8080/<contexto>/sistema?

logica=AdicionaContato.

Masparacadaaçãoteríamosumif/elseif,tornandoaServletmuitogrande,comtodaregra

denegóciodosistemainteiro.

Podemosmelhorar fazendo refactoring de extrair métodos.Mas continuaríamos com uma classemuitogrande.

Seriamelhorcolocarcadaregradenegócio(comoinserircontato,removercontato,fazerrelatórioetc)emumaclasseseparada.Cadaação(regradenegócio)emnossaaplicaçãoestariaemumaclasse.

Entãovamosextrairanossa lógicaparadiferentesclasses,paraquenossaServletpudesse terumcódigomaisenxutocomoesse:

if(acao.equals("AdicionaContato")){newAdicionaContato().executa(request,response);}elseif(acao.equals("ListaContato")){newListaContatos().executa(request,response);}

EteríamosclassesAdicionaContato,ListaContatos,etccomummétodo(digamos,executa)

quefazalógicadenegóciosapropriada.

Porém, a cada lógica nova, lógica removida, alteração etc, temos que alterar essa servlet. Isso étrabalhosoemuitopropensoaerros.

Reparedoispontosnocódigoacima.Primeiroqueelepossuiomesmocomportamentodeswitch!

EswitchemJavaquasesemprepodesersubstituídocomvantagemporpolimorfismo,comoveremos

aseguir.Outraquestãoéquerecebemoscomoparâmetrojustamenteonomedaclassequechamamosemseguida.

9.4MELHORANDOOPROCESSO 121

Page 131: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Vamostentargeneralizarentão,queremosexecutaroseguintecódigo:

StringnomeDaClasse=request.getParameter("logica");newnomeDaClasse().executa(request,response);

Queremospegaronomedaclasseapartirdoparâmetroeinstanciá-la.Entretantonãopodemos,poisnomeDaClasseéonomedeumavariáveleocódigoacimanãoéválido.Onossoproblemaéquesó

sabemosoquevamosinstanciaremtempodeexecução(quandooparâmetrochegar)enãoemtempodecompilação.

Masapartirdonomedaclassenóspodemosrecuperarumobjetoquerepresentaráasinformaçõescontidas dentro daquela classe, como por exemplo atributos, métodos e construtores. Para queconsigamosesseobjeto,bastautilizarmosaclasseClassinvocandoométodoforNameindicandode

qualclassequeremosumarepresentação.IssonosretornaráumobjetodotipoClassrepresentandoa

classe.Comoabaixo:

StringnomeDaClasse="br.com.caelum.mvc.logica."+request.getParameter("logica");Classclasse=Class.forName(nomeDaClasse);

Ótimo,podemosterumarepresentaçãodeAdicionaContatooudeListaContato eassimpor

diante.Masprecisamosdealgumaformainstanciaressasclasses.

Já que umadas informações guardadas pelo objeto do tipoClass é o construtor, nós podemos

invocá-loparainstanciaraclasseatravésdométodonewInstance.

Objectobjeto=classe.newInstance();

Ecomochamarométodoexecuta?ReparequeotipodeclaradodonossoobjetoéObject.Dessa

forma,nãopodemoschamarométodoexecuta.Umaprimeiraalternativaseríamosfazernovamente

if/elseparasabermosqualéalógicaqueestásendoinvocada,comoabaixo:

StringnomeDaClasse="br.com.caelum.mvc."+request.getParameter("logica");Classclasse=Class.forName(nomeDaClasse);

Objectobjeto=classe.newInstance();

if(nomeDaClasse.equals("br.com.caelum.mvc.AdicionaContato")){((AdicionaContato)objeto).executa(request,response);}elseif(nomeDaClasse.equals("br.com.caelum.mvc.ListaContatos")){((ListaContatos)objeto).executa(request,response);}//eassimpordiante

Masestamosvoltandoparaoif/elsequeestávamosfugindonocomeço.Issonãoébom.Todo

esseif/elseéocasionadoporcontadotipoderetornodométodonewInstanceserObjectenós

tratarmoscadaumadenossaslógicasatravésdeumtipodiferente.

Repareque,tantoAdicionaContatoquantoListaContatos,sãoconsideradasLogicasdentro

122 9.4MELHORANDOOPROCESSO

Page 132: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

donossocontexto.OquepodemosfazerentãoétratarambascomoalgoquesigaocontratodeLogica

implementandoumainterfacedemesmonomequedeclareométodoexecuta:

publicinterfaceLogica{voidexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException;}

PodemossimplificarnossaServletparaexecutaralógicadeformapolimórficae,tudoaquiloque

fazíamosemaproximadamente8linhasdecódigo,podemosfazeremapenas2:

Logicalogica=(Logica)classe.newInstance();logica.executa(request,response);

Dessaforma,umalógicasimplesparalogaralgonoconsolepoderiaserequivalentea:

publicclassPrimeiraLogicaimplementsLogica{publicvoidexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{System.out.println("Executandoalogicaeredirecionando...");RequestDispatcherrd=req.getRequestDispatcher("primeira-logica.jsp");rd.forward(req,res);}}

Alguém precisa controlar então que ação será executada para cada requisição, e que JSP seráutilizado.Podemosusarumaservletpara isso,eentãoelapassaa sera servletcontroladoradanossaaplicação,chamandoaaçãocorretaefazendoodispatchparaoJSPdesejado.

Melhorandoaindamaisnossaservletcontroladora,poderíamosdeixarnelaaresponsabilidadedenosredirecionar para uma página JSP ou para qualquer outra lógica ao final da execução das lógicas,bastandoqueométodoexecutaretorneumsimplesString,eliminandotodaarepetiçãodecódigo

RequestDispatcher.

ComeçaríamosalterandoaassinaturadométodoexecutadainterfaceLogicaqueeravoid e

agoraretornaráString:

publicinterfaceLogica{Stringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException;

}

DepoisfaríamosaslógicasretornaremumStringcomonomedo.jspquedeveserchamadoaofinaldassuasexecuções.

publicclassPrimeiraLogicaimplementsLogica{publicStringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{System.out.println("Executandoalogicaeredirecionando...");

9.4MELHORANDOOPROCESSO 123

Page 133: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

return"primeira-logica.jsp";}}

Por fim, a servlet controladora deve receber esse String e implementar o código de

RequestDispatcher:

@WebServlet("/sistema")publicclassControllerServletextendsHttpServlet{

protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{

Stringparametro=request.getParameter("logica");StringnomeDaClasse="br.com.caelum.mvc.logica."+parametro;

try{Class<?>classe=Class.forName(nomeDaClasse);Logicalogica=(Logica)classe.newInstance();

//RecebeoStringapósaexecuçãodalógicaStringpagina=logica.executa(request,response);

//FazoforwardparaapáginaJSPrequest.getRequestDispatcher(pagina).forward(request,response);

}catch(Exceptione){thrownewServletException("Alógicadenegócioscausouumaexceção",e);}}}

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

NotequeométodoforNamedaclasseClassretornaumobjetodotipoClass,masesseobjetoé

novo?Foirecicladoatravésdeumcachedessesobjetos?

Agoraéamelhorhoradeaprenderalgonovo

9.5RETOMANDOODESIGNPATTERNFACTORY

124 9.5RETOMANDOODESIGNPATTERNFACTORY

Page 134: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

ReparequenãosabemosoqueaconteceexatamentedentrodométodoforName,masaoinvocá-lo

eaexecuçãoocorrercomsucesso,sabemosqueaclassequefoipassadaemformadeStringfoilidae

inicializadadentrodavirtualmachine.

Na primeira chamada aClass.forName para determinada classe, ela é inicializada. Já em uma

chamadaposterior,Class.forNamedevolveaclassequejáfoilidaeestánamemória,tudoissosem

queafeteonossocódigo.

Esse exemplo do Class.forName é ótimo para mostrar que qualquer código que isola a

instanciaçãoatravésdealgumrecursodiferentedoconstrutoréumafactory.

1. Crieasuainterfacenopacotebr.com.caelum.mvc.logica:

publicinterfaceLogica{Stringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException;}

1. CrieumaimplementaçãodainterfaceLogica,nossaclassePrimeiraLogica,tambémnopacote

br.com.caelum.mvc.logica:

publicclassPrimeiraLogicaimplementsLogica{publicStringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{

System.out.println("Executandoalogica...");

System.out.println("RetornandoonomedapáginaJSP...");return"primeira-logica.jsp";

}}

1. FaçaumarquivoJSPchamadoprimeira-logica.jspdentrododiretórioWebContent:

<html><body><h1>Páginadanossaprimeiralógica</h1></body></html>

2. VamosescrevernossaServletquecoordenaráofluxodanossaaplicação.

CriesuaservletchamadaControllerServletnopacotebr.com.caelum.mvc.servlet:

@WebServlet("/mvc")publicclassControllerServletextendsHttpServlet{protectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse)

9.6 EXERCÍCIOS: CRIANDO NOSSAS LÓGICAS E A SERVLET DECONTROLE

9.6EXERCÍCIOS:CRIANDONOSSASLÓGICASEASERVLETDECONTROLE 125

Page 135: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

throwsServletException,IOException{

Stringparametro=request.getParameter("logica");StringnomeDaClasse="br.com.caelum.mvc.logica."+parametro;

try{Classclasse=Class.forName(nomeDaClasse);

Logicalogica=(Logica)classe.newInstance();Stringpagina=logica.executa(request,response);

request.getRequestDispatcher(pagina).forward(request,response);

}catch(Exceptione){thrownewServletException("Alógicadenegócioscausouumaexceção",e);}}}

1. Testeaurlhttp://localhost:8080/fj21-agenda/mvc?logica=PrimeiraLogica

1. Crie uma nova classe chamada RemoveContatoLogica no mesmo pacote

br.com.caelum.mvc.logica.DevemosimplementarainterfaceLogicaedurantesuaexecução

receberemosumidpelorequesteremoveremosocontatonobancoapartirdesteid.

publicclassRemoveContatoLogicaimplementsLogica{

publicStringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{

longid=Long.parseLong(req.getParameter("id"));

Contatocontato=newContato();contato.setId(id);

ContatoDaodao=newContatoDao();dao.exclui(contato);

System.out.println("Excluindocontato...");

return"lista-contatos.jsp";}

9.7 EXERCÍCIOS: CRIANDO UMA LÓGICA PARA REMOVERCONTATOS

126 9.7EXERCÍCIOS:CRIANDOUMALÓGICAPARAREMOVERCONTATOS

Page 136: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

1. Napáginalista-contatos.jsp, vamos acrescentar uma colunana tabela que lista os contatos

comumlinkchamandoalógicaderemoçãoepassandooiddocontato:

<!--códigoomitido-->

<c:forEachvar="contato"items="${dao.lista}"><tr>

<!--códigoomitido-->

<td><ahref="mvc?logica=RemoveContatoLogica&id=${contato.id}">Remover</a></td></tr></c:forEach>

<!--códigoomitido-->

1. Testea lógicade remoçãoacessandohttp://localhost:8080/fj21-agenda/lista-contatos.jspeclicandoemalgumlinkRemover.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

Agora que todo nosso processamento está passando pela Servlet controladora e conseguimosorganizarnossocódigoemcamadasbemdefinidas,nosdeparamoscomumasituaçãoqueaindaestáumpoucodistantedoideal.

Se olharmos a página lista-contatos.jsp veremos que para fazer a listagem dos contatos

funcionar estamos criando uma instância da classe ContatoDao para utilizá-la depois no

<c:forEach>recuperandoumalistadecontatos.

EditoraCasadoCódigocomlivrosdeumaformadiferente

9.8FAZENDOALÓGICAPARALISTAROSCONTATOS

9.8FAZENDOALÓGICAPARALISTAROSCONTATOS 127

Page 137: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<jsp:useBeanid="dao"class="br.com.caelum.agenda.dao.ContatoDao"/>

<table><c:forEachvar="contato"items="${dao.lista}"><tr><td>${contato.nome}</td><!--códigoomitido--></tr></c:forEach></table>

Instanciar objetos da camada Model na camada View não é considerada uma boa prática naarquiteturaMVC(antipattern).

Podemos resolver facilmente isso tranferindo essa responsabilidade demontar a lista de contatosparaumalógicaListaContatosLogicaedepoispassá-laprontadiretoparaoJSPpelorequest.

Paraguardarmosalgonarequisição,precisamosinvocarométodo.setAttribute() no request.

Passamos para essemétodo uma identificação para o objeto que estamos guardando na requisição etambémpassamosopróprioobjetoparaserguardadonorequest.

publicclassListaContatosLogicaimplementsLogica{

publicStringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{

//MontaalistadecontatosList<Contato>contatos=newContatoDao().getLista();

//Guardaalistanorequestreq.setAttribute("contatos",contatos);

return"lista-contatos.jsp";}}

Agora é só ajustar a página lista-contatos.jsp para não instanciar mais o ContatoDao ,

removendoalinha<jsp:useBeanid="dao"class="br.com.caelum.agenda.dao.ContatoDao"/>,

edepoisfazercomqueo<c:forEach>usealistadecontatosquefoicolocadanorequest:

<c:forEachvar="contato"items="${contatos}">

1. Crie uma nova classe chamada ListaContatosLogica no mesmo pacote

br.com.caelum.mvc.logica. Devemos implementar nela a interface Logica e, durante sua

execução vamos criar uma lista de contatos através de uma instância da classe ContatoDao ,

guardá-lanorequesteretornarparaaservletcontroladora:

publicclassListaContatosLogicaimplementsLogica{

publicStringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{

9.9EXERCÍCIOS:LÓGICAPARALISTARCONTATOS

128 9.9EXERCÍCIOS:LÓGICAPARALISTARCONTATOS

Page 138: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

List<Contato>contatos=newContatoDao().getLista();

req.setAttribute("contatos",contatos);

return"lista-contatos.jsp";}}

1. Agora,vamosmodificarapáginalista-contatos.jspparanãoinstanciarmaisContatoDaona

View, removendo a linha <jsp:useBean id="dao"

class="br.com.caelum.agenda.dao.ContatoDao"/>,ealteraro<c:forEach>parausaralista

decontatosquefoicolocadapelalógicanorequestaoinvésde${dao.lista}:

<c:forEachvar="contato"items="${contatos}">

1. Agora podemos testar chamando: http://localhost:8080/fj21-agenda/mvc?

logica=ListaContatosLogica

2. Depoisdessasalterações, seránecessárioalteraro retornodaclasseRemoveContatoLogica pois

agoraachamadadiretadolista-contatos.jsp nãoémaispossível.Devemosagora chamara

lógicaquelistaoscontatos:

publicclassRemoveContatoLogicaimplementsLogica{

publicStringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{

//códigoomitido

return"mvc?logica=ListaContatosLogica";}

}

Como alteramos nossa listagem para ser acessada pela lógica ListaContatosLogica , se

acessarmosa jsplista-contatos.jsp diretamentepelonavegador, a páginanãomostrará nenhum

contato.Precisamosentãosemprepassarpelalógica,queporsuavezdisponibilizaráalistagemparaapágina.

Portanto,nãodevemospermitirqueousuárioacessediretamentenossapágina.Paraimpossibilitaresteacessodireto,colocaremosnossaspáginasdentrododiretórioWEB-INF/jsp.

AgoraqueestamosusandoMVC,umaboapráticaénãodeixarmososusuáriosacessaremnossaspáginasdiretamente,esimpassandosempreporumalógica.

Nossalógicadelistagemficarádaseguinteforma:

publicclassListaContatosLogicaimplementsLogica{

9.10ESCONDENDONOSSASPÁGINAS

9.10ESCONDENDONOSSASPÁGINAS 129

Page 139: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicStringexecuta(HttpServletRequestreq,HttpServletResponseres)throwsException{

List<Contato>contatos=newContatoDao().getLista();

req.setAttribute("contatos",contatos);

return"/WEB-INF/jsp/lista-contatos.jsp";}

Alémdisso,sequisermosaplicarestemesmoconceitoparaasdemaisjsps,precisaremosalterarasdemaislógicascorrespondentesacrescentandoodiretórioWEB-INF/jspantesdonomedapágina.

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

1. CrieumalógicachamadaAlteraContatoLogicaetesteamesmaatravésdeumlinknalistagem

dalista-contatos.jsp.Lembre-se,antesdechamaressalógicaéprecisocriarumaoutralógica

quemostreosdadosdocontatoemumanovapágina,permitindoassimaalteraçãodosdados,esódepois,nocliquedeumbotão,queaalteraçãoserádefatoefetivada.

2. Criealógicadeadicionarcontatos(AdicionaContatoLogica).Reparequeelaébemparecidacom

aAlteraContatoLogica.Crie um formulário de adiçãodenovo contato.Coloqueum linkpara

adicionarnovoscontatosdentrodolista-contatos.jsp.

3. Desafio:Aslógicasdeadiçãoedealteraçãoficarammuitoparecidas.Tentecriarumaversãodeumadessas lógicas que faça as duas. Dica: A única diferença entre as duas é a presença ou não doparâmetroId.

4. Desafio: Altere seu projeto para que nenhuma jsp seja acessível diretamente, colocando-as nodiretórioWEB-INF/jsp.Modifique também suas lógicas de acordo.OBS:Deverá ser criadaumanovalógicaparaavisualizaçãodoformuláriodeadiçãodecontatos.

JáconheceoscursosonlineAlura?

9.11EXERCÍCIOSOPCIONAIS

130 9.11EXERCÍCIOSOPCIONAIS

Page 140: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Generalizandoomodeloacima,podemosdarnomesacadaumadaspartesdessanossaarquitetura.QueméresponsávelporapresentarosresultadosnapáginawebéchamadodeApresentação(View).

Aservlet(eauxiliares)quefazosdispatchesparaquemdeveexecutardeterminadatarefaéchamadadeControladora(Controller).

Asclassesque representamsuasentidadeseasque teajudamaarmazenarebuscarosdados sãochamadasdeModelo(Model).

EssestrêsformamumpadrãoarquiteturalchamadodeMVC,ouModelViewController.Elepodesofrervariaçõesdediversasmaneiras.OqueoMVCgaranteéaseparaçãodetarefas,facilitandoassimareescritadealgumaparte,eamanutençãodocódigo.

OfamosoStrutsajudavocêaimplementaroMVC,poistemumacontroladorajápronta,comumasériedeferramentasparateauxiliar.OHibernatepodeserusadocomoModel,porexemplo.EcomoViewvocênãoprecisausarsóJSP,podeusaraferramentaVelocity,porexemplo.

Hádiversasopçõesparaacamadadecontrolenomercado.Vejaumpoucosobrealgumasdelas:

StrutsAction-ocontroladormaisfamosodomercadoJava,éutilizadoprincipalmenteporseromais divulgado e com tutoriais mais acessíveis. Possui vantagens características do MVC edesvantagensquenaépocaaindanãoerampercebidas.ÉocontroladorpedidonamaiorpartedasvagasemJavahojeemdia.ÉumprojetoquenãoterágrandesatualizaçõespoisaequipedelesejuntoucomoWebWorkparafazeroStruts2,novaversãodoStrutsincompatívelcomaprimeiraetotalmentebaseadanoWebWork.

VRaptor - desenvolvido inicialmente por profissionais daCaelume baseado emdiversas ideiasdoscontroladoresmencionadosacima,oVRaptorusaoconceitodefavorecerConvençõesemvezdeConfiguraçõesparaminimizarousodeXMLeanotaçõesemsuaaplicaçãoWeb.

JSF - JSF é uma especificação Java para frameworksMVC. Ele é baseado em componentes epossui várias facilidades para desenvolver a interface gráfica.Devido ao fato de ser um padrãooficial,eleébastanteadotado.OJSFéensinadoemdetalhesnonossocursoFJ-26.

SpringMVC-éumapartedoSpringFrameworkfocadoemimplementarumcontroladorMVC.ÉfácildeusaremsuasúltimasversõesetemavantagemdeseintegraratodaaestruturadoSpringcomváriastecnologiasdisponíveis.

9.12MODELVIEWCONTROLLER

9.13LISTADETECNOLOGIAS:CAMADADECONTROLE

9.12MODELVIEWCONTROLLER 131

Page 141: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

Temostambémdiversasopçõesparaacamadadevisualização.Umpoucosobrealgumasdelas:

JSP - como já vimos, o JavaServer Pages, temos umaboa ideia do que ele é, suas vantagens edesvantagens.Ousodetaglibs(aJSTLporexemplo)eexpressionlanguageémuitoimportantesevocêescolherJSPparaoseuprojeto.Éaescolhadomercadohojeemdia.

Velocity-umprojetoantigo,noqualaELdoJSPsebaseou,capazdefazertudooquevocêprecisaparaasuapáginadeumamaneiraextremamentecompacta. IndicadopelaCaelumparaconhecerumpoucomaissobreoutrasopçõesparacamadadevisualização.

Freemarker-similaraoVelocityecomideiasdoJSP-comosuporteataglibs-ofreemarkervemsendocadavezmaisutilizado,elepossuidiversasferramentasnahoradeformatarseutextoquefacilitammuitootrabalhododesigner.

Sitemesh - não é uma alternativa para as ferramentas anterioresmas sim umamaneira de criartemplatesparaseusite,comumaideiamuitoparecidacomostrutstiles,porémgenérica:funcionainclusivecomoutraslinguagenscomoPHPetc.

Em pequenas equipes, é importante uma conversa para mostrar exemplos de cada uma dastecnologiasacimaparaodesigner,afinalquemvai trabalharcomaspáginaséele.Aqueelepreferir,vocêusa,afinaltodaselasfazemomesmodemaneirasdiferentes.Comoemumprojetoécomumterpoucos designers e muitos programadores, talvez seja proveitoso facilitar um pouco o trabalho paraaqueles.

VocêpodetambémfazerocursodatadessaapostilanaCaelum

9.14LISTADETECNOLOGIAS:CAMADADEVISUALIZAÇÃO

9.15 DISCUSSÃO EM AULA: OS PADRÕES COMMAND E FRONTCONTROLLER

132 9.14LISTADETECNOLOGIAS:CAMADADEVISUALIZAÇÃO

Page 142: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO10

"Aartenuncaestáterminada,apenasabandonada."--LeonardoDaVinci

Aotérminodessecapítulo,vocêserácapazde:

criarclassesquefiltramarequisiçãoearesposta;guardarobjetosnarequisição;descreveroqueéinjeçãodedependências;descreveroqueéinversãodecontrole;

Em qualquer aplicação surgem requisitos que não são diretamente relacionados com a regra denegócio.Umexemploclássicodessesrequisitosnãofuncionaiséaauditoria(Logging).Queremoslogaraschamadasdeumalógicadanossaaplicação.Outrosexemplossãoautorização,tratamentodeerrooucriptografia.Existemváriosoutros,masoque todoseles tememcomuméquenão são relacionadoscomasregrasdenegócios.

A pergunta como implementar estas funcionalidades, nos vem a cabeça. A primeira ideia seriacolocar o código diretamente na classe que possui a lógica. A classe seguinte mostra através depseudocódigoaschamadasparafazerauditoriaeautorização:

publicclassRemoveContatoLogicimplementsLogica{

publicvoidexecuta(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{

//auditoriaLogger.info("acessandoremovecontatologic");

//autorizaçãoif(!usuario.ehCliente()){request.getRequestDispatcher("/acessoNegado.jsp").forward(request,response);}

//todalógicapararemoverocontatoaqui//...}}

RECURSOSIMPORTANTES:FILTROS

10.1REDUZINDOOACOPLAMENTOCOMFILTROS

10RECURSOSIMPORTANTES:FILTROS 133

Page 143: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Podemosverquealémdalógicaéprecisoimplementarosoutrosrequisitos,masnãosóapenasnalógica que altera o contato, também é necessário colocar omesmo código nas lógicas que adiciona,removeoufazalistagemdoscontatos.Issopodepiorarpensandoqueexistemmuitomaisrequisitosnãofuncionais, como resultado o código aumenta em cada lógica. Desse jeito criamos um acoplamentomuitoforteentrealogicaeaimplementaçãodosrequisitosnãofuncionais.Ograndeproblemaéqueosmesmosficamespalhadosemtodasaslógicas.Aimagemabaixoilustraesseacoplamento:

A API de Servlets nos provê um mecanismo para tirar esse acoplamento e isolar essecomportamento,quesãoosFiltros.Filtrossãoclassesquepermitemqueexecutemoscódigoantesdarequisiçãoetambémdepoisquearespostafoigerada.

Umaboaanalogiaépensarqueaslógicassãoquartosemumacasa.Paraacessarumquartoéprecisopassarporváriasportas.Asportassãoosfiltros,ondevocêpassanaidaenavolta.Cadafiltroencapsulaapenasuma responsabilidade,ou sejaum filtropara fazer auditoria,outropara fazer a segurançaetc.Entãoépossívelusarváriosfiltrosemconjunto.Umaportatambémpodeficarfechada,casoousuárionão possua acesso a lógica, ou seja, o filtro pode negar a execução de uma lógica. Veja a imagemseguintequemostraosfiltrosaplicadosnoexemploanterior:

134 10RECURSOSIMPORTANTES:FILTROS

Page 144: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

A grande vantagem é que cada requisito fica em um lugar só e conseguimos desacoplar nossaslógicas.

ParacriarmosfiltrosutilizandoaAPIdeServletsdoJavaEE5,temosasmesmasdificuldadesquetemosquandovamosdefinirServlets.Paracadafiltroénecessáriocriarmosaclassequeimplementa

ainterfacejavax.servlet.Filteredepoisdeclararmosofiltronoweb.xml, alémde termosque

declararparaquaisURL'saquelefiltroseráaplicado.

Configuraçãodeumfiltronoweb.xml:

<filter><filter-name>meuFiltro</filter-name><filter-class>br.com.caelum.filtro.MeuFiltro</filter-class></filter>

<filter-mapping><filter-name>meuFiltro</filter-name><url-pattern>/*</url-pattern></filter-mapping>

MasparadefinirmosumfiltrousandoanovaAPIdeServletsdoJavaEE6,bastaapenascriarmosuma classe que implementa a interface javax.servlet.Filter e anotarmos a classe com

@WebFilter.Podemosaproveitarepassarcomoparâmetronaanotaçãoopadrãoderequisiçõesque

serãofiltradas:

@WebFilter("/oi")publicclassMeuFiltroimplementsFilter{publicvoiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain){//...}}

Destaformaindicamosquetodasasrequisiçõesvindasapartirde/oiserãofiltradase,portanto,o

filtroseráaplicadoemcadarequisição.

10RECURSOSIMPORTANTES:FILTROS 135

Page 145: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Épossível usar um filtromais especifico.Por exemplo, podemos filtrar todas as requisiçõesparapaginasJSPs:

@WebFilter("/*.jsp")publicclassMeuFiltroimplementsFilter{publicvoiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain){//...}}

Ouumfiltromaisamplo,filtrandoTODASasrequisiçõesdaaplicação:

@WebFilter("/*")publicclassMeuFiltroimplementsFilter{publicvoiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain){//...}}

Ao implementar a interface Filter, temos que implementar 3 métodos: init, destroy e

doFilter.

Os métodos init e destroy possuem a mesma função dos métodos de mesmo nome da

Servlet,ouseja,executaralgoquandooseufiltroécarregadopelocontainerequandoédescarregado

pelocontainer.

Ométodoque fará todooprocessamentoquequeremosexecutaréodoFilter, que recebe três

parâmetros:ServletRequest,ServletResponseeFilterChain.

@WebFilter("/*")publicclassFiltroTempoDeExecucaoimplementsFilter{

//implementaçãodoinitedestroy

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{

//todooprocessamentovaiaqui}}

PercebaasemelhançadessemétodocomométodoservicedaclasseServlet.Aideiadofiltroé

também processar requests,mas ele poderá fazer isso demaneiramais genérica para vários tipos derequests.Masumfiltrovaialémdeumservlet,comumfiltropodemostambémfechar"aporta".EssepodervemdoargumentoFilterChain(acadeiadefiltros).Elenospermiteindicaraocontainerqueo

requestdeveprosseguirseuprocessamento. IssoéfeitocomumachamadadométododoFilter da

classeFilterChain:

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)

136 10RECURSOSIMPORTANTES:FILTROS

Page 146: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

throwsIOException,ServletException{

//passapelaportachain.doFilter(request,response);}

Um filtro não serve para processar toda a requisição. A ideia é ele interceptar vários requestssemelhantes, executar algo, mas depois permitir que o processamento normal do request prossigaatravésdasServletseJSPsnormais.

Qualquer código colocado antes da chamada chain.doFilter(request,response) será

executadonaida,qualquercódigodepoisnavolta.Comissopodemosfazerumverificaçãodeacessoantesdalógica,ouabrirumrecurso(conexãooutransação)antesenavoltafecharomesmo.Umfiltroéidealparafazertratamentodeerroroumedirotempodeexecução.

A única coisa que precisamos fazer para que o nosso filtro funcione é registrá-lo, para que ocontainer saiba que ele precisa ser executado. Fazemos isso de forma simples, usando atributos daanotação@WebFilter. Através dos atributos, declaramos o filtro e quais URLs ou Servlets serão

filtradas.

O atributo filterName define um nome (ou alias) para o filtro. Se não definirmos o atributofilterName para nosso filtro, o nome dele será o nome completo da classe, damesma forma que

acontececomasServlets.ParadefinirmosquaisURLpassarãopelonossofiltro,podemosfazê-lode

maneira similaràanotaçã[email protected] aquele filtropara apenasumaURL,

passamos através do parâmetro na anotação @WebFilter como foi feito no exemplo acima

-@WebFilter("/oi").Mas,sequisermosdefinirquemaisdeumaURLseráfiltrada,podemosusaro

atributourlPatterns:

@WebFilter(filterName="MeuFiltro",ulrPatterns={"/oi","/ola"})publicclassMeuFiltroimplementsFilter{publicvoiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain){//...}}

PodemosaindaconfigurarquaisservletsserãofiltradosporaquelefiltrodeclarandoseusnomesnoatributoservletNames.Porexemplo:

@WebFilter(filterName="MeuFiltro",servletNames={"meuServlet","outroServlet"})publicclassMeuFiltroimplementsFilter{publicvoiddoFilter(ServletRequestreq,ServletResponseres,FilterChainchain){//...}}

10RECURSOSIMPORTANTES:FILTROS 137

Page 147: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

OUTRASANOTAÇÕES

ExistemoutrasanotaçõespresentesnaAPIServlets3.0:

@WEBLISTENER -Utilizada para definirListeners de eventos que podemocorrer emváriospontosdasuaaplicação;equivaleaodehoje;

@WEBINITPARAM - Utilizada para especificar parâmetros de inicialização que podem serpassadosparaServletseFiltros.Podeserpassadacomoparâmetroparaasanotações

@WebServlete@WebFilter;equivaleaodehoje;

@MULTIPARTCONFIG -Utilizada para definir que um determinado Servlet receberá uma

requisiçãodotipomime/multipart.

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

1. Vamoscriaronossofiltroparamedirotempodeexecuçãodeumarequisição.

Crie uma nova classe chamada FiltroTempoDeExecucao no pacote

br.com.caelum.agenda.filtroefaçaelaimplementarainterfacejavax.servlet.Filter

Anote-acom@WebFilteredigaqueTODASasrequisiçõesparaanossaaplicaçãodevemser

filtradas(@WebFilter("/*")).

DeixeosmétodosinitedestroyvazioseimplementeodoFilter:

Seuslivrosdetecnologiaparecemdoséculopassado?

10.2 EXERCÍCIOS OPCIONAIS: FILTRO PARA MEDIR O TEMPO DEEXECUÇÃO

138 10.2EXERCÍCIOSOPCIONAIS:FILTROPARAMEDIROTEMPODEEXECUÇÃO

Page 148: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

@WebFilter("/*")publicclassFiltroTempoDeExecucaoimplementsFilter{publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{

longtempoInicial=System.currentTimeMillis();

chain.doFilter(request,response);

longtempoFinal=System.currentTimeMillis();Stringuri=((HttpServletRequest)request).getRequestURI();Stringparametros=((HttpServletRequest)request).getParameter("logica");System.out.println("Tempodarequisicaode"+uri+"?logica="+parametros+"demorou(ms):"+(tempoFinal-tempoInicial));

}//métodosinitedestroyomitidos}

Reinicie o servidor e acesse http://localhost:8080/fj21-agenda/mvc?logica=ListaContatosLogica

Procureasaídanoconsole.

Nossaaplicaçãodeagendanecessita,emváriosmomentos,deumaconexãocomobancodedadose,paraisso,onossoDAOinvocaemseuconstrutoraConnectionFactorypedindoparaamesmauma

novaconexão.Masemquallugarficaráofechamentodaconexão?

publicclassContatoDao{privateConnectionconnection;

publicContatoDao(){this.connection=newConnectionFactory().getConnection();}

//métodosadiciona,remove,getListaetc//ondefechamosaconexão?}

Até omomento, não estamos nos preocupando como fechamento das conexões como banco dedados. Isso é uma péssima prática para uma aplicação que vai para produção. Estamos deixandoconexões abertas e sobrecarregando o servidor de banco de dados, que pode aguentar apenas umdeterminado número de conexões abertas, o que fará com que sua aplicação pare de funcionarsubitamente.

OutroproblemaquetemosaoseguiressaestratégiadeadquirirconexãonoconstrutordosDAOsé

quando queremos usar dois DAOs diferentes, por exemplo ContatoDao e FornecedorDao. Ao

10.3PROBLEMASNACRIAÇÃODASCONEXÕES

10.3PROBLEMASNACRIAÇÃODASCONEXÕES 139

Page 149: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

instanciarmos ambos os DAOs, vamos abrir duas conexões, enquanto poderíamos abrir apenas uma

conexãoparafazerasduasoperações.Deoutraformaficaimpossívelrealizarasoperaçõesnumaúnicatransação.

JápercebemosquenãoéumaboaideiacolocarmosacriaçãodaconexãonoconstrutordosnossosDAOs.Masqualéolugaridealparacriarmosessaconexãocomobancodedados?

PoderíamoscriaraconexãodentrodecadamétododoDAO,masnessecaso,seprecisássemosusar

dois métodos diferentes do DAO em uma mesma operação, novamente abriríamos mais de uma

conexão. Dessa forma, abrir e fechar as conexões dentro dosmétodos dos DAOs também não nos

pareceumaboaalternativa.

Precisamos,dealgumaforma,criaraconexãoefazercomqueessamesmaconexãopossaserusadaportodososseusDAOsemumadeterminadarequisição.Assim,podemoscriarnossasconexõescomo

bancodedadosdentrodenossasServlets(oulógicas,nocasodonossoframeworkMVCvistono

capítuloanterior)eapenaspassá-lasparaoDAOquevamosutilizar.Paraisso,nossosDAOsdeverãoter

umconstrutorquerecebaConnection.

Vejamos:

publicclassContatoDao{privateConnectionconnection;

publicContatoDao(Connectionconnection){this.connection=connection;}

//métodosadiciona,remove,getListaetc}

publicclassAdicionaContatoLogicimplementsLogica{publicStringexecuta(HttpServletRequestrequest,HttpServletResponseresponse){Contatocontato=//contatomontadocomosdadosdorequest

Connectionconnection=newConnectionFactory().getConnection();

//passaconexãoproconstrutorContatoDaodao=newContatoDao(connection);dao.adiciona(contato);

connection.close();

//retornaparaoJSP}}

Isso já é uma grande evolução com relação ao que tínhamos no começo mas ainda não é uma

10.4TENTANDOOUTRASESTRATÉGIAS

140 10.4TENTANDOOUTRASESTRATÉGIAS

Page 150: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

solução muito boa. Acoplamos com a ConnectionFactory todas as nossas lógicas que precisam

utilizar DAOs. E, em orientação a objetos, não é uma boa prática deixarmos nossas classes com

acoplamentoalto.

INJEÇÃODEDEPENDÊNCIASEINVERSÃODECONTROLE

Aonão fazermosmais a criaçãoda conexãodentrodoContatoDaomas sim recebermos a

Connectiondaqualdependemosatravésdoconstrutor,dizemosqueonossoDAOnãotemmais

o controle sobre a criação da Connection e, por isso, estamos Invertendo oControle dessacriação.AúnicacoisaqueonossoDAOdizéqueeledependedeumaConnectionatravésdo

construtore,porisso,onossoDAOprecisaqueesseobjetodotipoConnectionsejarecebido,ou

seja,eleesperaqueadependênciasejainjetada.

Injeção de Dependências e Inversão de Controle são conceitos muito importantes nasaplicaçõesatuaisenósasestudaremoscommaisdetalhesaindanocurso.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

NãoqueremostambémqueanossalógicaconheçaaclasseConnectionFactorymas,aindaassim,

precisamosqueelapossuaaconexãoparaquepossamosrepassá-laparaoDAO.

Paradiminuirmosesseacoplamento,queremosque,semprequechegarumarequisiçãoparaanossaaplicação, uma conexão seja aberta e, depois que essa requisição for processada, ela seja fechada.Tambémpodemosadicionaro tratamentoa transaçãoaqui, se acharmosnecessário.Precisamosentãointerceptartodarequisiçãoparaexecutaressesprocedimentos.

Agoraéamelhorhoradeaprenderalgonovo

10.5REDUZINDOOACOPLAMENTOCOMFILTROS

10.1REDUZINDOOACOPLAMENTOCOMFILTROS 141

Page 151: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

ComojávistoosFiltrospermitemqueexecutemoscódigoantesdarequisiçãoetambémdepoisquearespostafoigerada.Idealparaabrirumaconexãoantesefecharnavolta.

Vamosentãoimplementarumfiltrocomessecomportamento:

@WebFilter("/*")publicclassFiltroConexaoimplementsFilter{//implementaçãodoinitedestroy,senecessário

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{

//abreumaconexãoConnectionconnection=newConnectionFactory().getConnection();

//indicaqueoprocessamentodorequestdeveprosseguirchain.doFilter(request,response);

//fechaconexãoconnection.close();}}

Comaconexãoaberta,precisamosentãofazercomquearequisiçãosaiadonossofiltroeváparaopróximo passo, seja ele um outro filtro, ou uma Servlet ou um JSP. Dessa forma, nossa lógica denegóciopodeexecutarnormalmente.Para isso,usamoso argumentoFilterChain quenospermite

indicaraocontainerqueorequestdeveprosseguirseuprocessamento.IssoéfeitocomumachamadaaodoFilterdoFilterChain:

Atéagora,conseguimosabrirumaconexãonocomeçodosrequests,prosseguiroprocessamentodorequestnormalmenteefecharaconexãoaposdaexecução.Masnossaslógicasvãoexecutar,digamos,manipulações de Contatos e vão precisar da conexão aberta no filtro. Mas como acessá-la? Como,dentrodeumaServlet,pegarumobjetocriadodentrodeumfiltro,umaoutraclasse?

Aideiaéassociar(pendurar)dealgumaformaaconexãocriadaaorequestatual.IssoporquetantoofiltroquantoaServletestãonomesmorequesteporque,comodefinimos,asconexõesvãoserabertasporrequests.

142 10.5REDUZINDOOACOPLAMENTOCOMFILTROS

Page 152: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Paraguardarmosalgonarequisição,precisamosinvocarométodosetAttributenorequest.

Passamos para essemétodo uma identificação para o objeto que estamos guardando na requisição etambémpassamosopróprioobjetoparaserguardadonorequest.

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain){

Connectionconnection=newConnectionFactory().getConnection();

//"penduraumobjetonoRequest"request.setAttribute("connection",connection);

chain.doFilter(request,response);

connection.close();}

AoinvocarmosodoFilter,arequisiçãoseguiráoseufluxonormallevandooobjetoconnection

junto.Oqueousuário requisitou será entãoexecutadoaté a resposta sergerada (porumaServletouJSP). Após isso, a execução volta para o ponto imediatamente abaixo da invocação dochain.doFilter. Ou seja, através de um filtro conseguimos executar algo antes do request serprocessadoedepoisdarespostasergerada.

Pronto,nossoFiltroéoúnicopontodanossaaplicaçãoquecriaráconexões.

Repare comousamosowildcard no parâmetro da anotação para indicar que todas as requisiçõesserãofiltradase,portanto,terãoumaconexãoabertajádisponível.

Só falta na nossa lógica pegarmos a conexão que guardamos no request . Para isso basta

invocarmosométodogetAttributenorequest.Nossalógicaficarádaseguintemaneira:

publicclassAdicionaContatoLogicimplementsLogica{

publicStringexecuta(HttpServletRequestrequest,HttpServletResponseresponse)

10.5REDUZINDOOACOPLAMENTOCOMFILTROS 143

Page 153: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

throwsException{

Contatocontato=//contatomontadocomosdadosdorequest

//buscandoaconexãodorequestConnectionconnection=(Connection)request.getAttribute("connection");

ContatoDaodao=newContatoDao(connection);dao.adiciona(contato);

//fazoreturndoJSPcomodecostume}}

Umaoutragrandevantagemdessedesacoplamentoéqueeletornaonossocódigomaisfácildesetestarunitariamente,assuntoqueaprendemosepraticamosbastantenocursoFJ-22.

1. Vamoscriaronossofiltroparaabrirefecharaconexãocomobancodedados

CrieumanovaclassechamadaFiltroConexaonopacotebr.com.caelum.agenda.filtro e

façaelaimplementarainterfacejavax.servlet.Filter

Anote-acom@WebFilter("/*")para registraro filtronocontainer e fazer comque todasas

requisiçõespassemporele:

DeixeosmétodosinitedestroyvazioseimplementeodoFilter:

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{

try{Connectionconnection=newConnectionFactory().getConnection();

//pendurandoaconnectionnarequisiçãorequest.setAttribute("conexao",connection);

chain.doFilter(request,response);

connection.close();}catch(SQLExceptione){thrownewServletException(e);}}

2. CrieumconstrutornoseuContatoDao(casonãoexista)querecebaConnectionearmazene-ano

atributo:

publicclassContatoDao{privateConnectionconnection;

publicContatoDao(Connectionconnection){

10.6EXERCÍCIOS:FILTROS

144 10.6EXERCÍCIOS:FILTROS

Page 154: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

this.connection=connection;}

//outroconstrutoremétodosdoDAO}

3. Na suaRemoveContatoLogica, criada no capítulo anterior, busque a conexão no request, e

repasse-aparaoDAO.ProcurenalógicaacriaçãodoDAOefaçaasalterações:

publicclassRemoveContatoLogicaimplementsLogica{publicStringexecuta(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{

//...

//(procureoContatoDaonocódigoexistente)//buscaaconexãopenduradanarequisiçãoConnectionconnection=(Connection)request.getAttribute("conexao");

//passeaconexãonoconstrutorContatoDaodao=newContatoDao(connection);

//...}}

OuvocêpodefazeressamesmamodificaçãonanossaantigaAdicionaContatoServlet.

1. Removaumcontatonasuaaplicaçãoeverifiquequetudocontinuafuncionandonormalmente.

10.6EXERCÍCIOS:FILTROS 145

Page 155: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO11

"Umhomempintacomseucérebroenãocomsuasmãos."--Michelangelo

Nessecapítulo,vocêaprenderá:

Porqueutilizarframeworks;ComofuncionaoframeworkSpringMVC;AsdiferentesformasdesetrabalharcomoSpringMVC.

Quandoestamosdesenvolvendoaplicações,emqualquer linguagem,queremosnospreocuparcominfraestrutura omínimo possível. Isso não é diferente quando trabalhamos com uma aplicaçãoWeb.Imagine termos que lidar diretamente com o protocolo HTTP a todo momento que tivermos quedesenvolverumafuncionalidadequalquer.Nesseponto,oscontainerseaAPIdeServletsencapsulamoprotocoloparaquenãoprecisemoslidardiretamentecomele,masmesmoassimexistemuitotrabalhorepetitivoqueprecisamosfazerparaquepossamosdesenvolvernossalógica.

Um exemplo desse trabalho repetitivo que fazíamos era a conversão da data. Como o protocoloHTTP sempre interpreta tudo como texto, é preciso transformar essa data em um objeto do tipo Calendar . Mas sempre que precisamos de uma data temos essa mesma conversão usando a

SimpleDateFormat.

Outroexemploé,queparagravarmosumobjetodo tipoContato, precisamospegar naAPIde

Servlets parâmetropor parâmetroparamontar umobjetodo tipoContato invocandoos setters

adequados.

NãoseriamuitomaisfácilquenossalógicarecebessedealgumaformaumobjetodotipoContato

já devidamente populado com os dados que vieram na requisição?Nosso trabalho seria apenas, porexemploinvocaroContatoDaopassandooContatoparaseradicionado.

OgrandeproblemaéqueestamosatreladosaAPIdeServlets que ainda exigemuito trabalho

braçal para desenvolvermos nossa lógica. E, justamente para resolver esse problema, começaram asurgir os frameworksMVC, comoobjetivodediminuir o impactodaAPIdeServlets emnosso

trabalhoefazercomquepassemosanospreocuparexclusivamentecomalógicadenegócios,queéo

SPRINGMVC

11.1PORQUEPRECISAMOSDEFRAMEWORKSMVC?

146 11SPRINGMVC

Page 156: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

códigoquepossuivalorparaaaplicação.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

LogosepercebeuqueotrabalhocomServletseJSPspurosnãoeratãoprodutivoeorganizado.AprópriaSuncomeçouafomentarousodopadrãoMVCedepatternscomoFrontController.Eramuitocomum as empresas implementarem esses padrões e criarem soluções baseadas emmini-frameworkscaseiros.

Mas logosepercebeuqueo retrabalhoeramuitograndedeprojetoparaprojeto,deempresaparaempresa.UsarMVCerabeminteressante,masreimplementaropadrãotodoacadaprojetocomeçouaserinviável.

OStrutsfoiumdosprimeirosframeworksMVCcomaideiadesecriarumcontroladorreutilizávelentre projetos. Ele foi lançado no ano 2000 com o objetivo de tornar mais simples a criação deaplicaçõesWebcomalinguagemJavaaodisponibilizarumasériedefuncionalidadesjáprontas.

Isso fez com que muitas pessoas o utilizassem para desenvolver suas aplicações, tornando-orapidamenteaprincipalsoluçãoMVCnomercadoJava.Umadasconsequênciasdissoéquehojeemdiaeleéumdosmaisutilizadosnomercado.

Noentanto,hoje,eleévistocomoumframeworkquedemandamuitotrabalho,justamenteportersidocriadohámuitotempo,quandomuitasdasfacilidadesdalinguagemJavaaindanãoexistiam.

PorissosurgiramoutrosframeworksMVC.AcomunidadedoStruts,porexemplo,uniuforçascoma de outro framework que começava a ganhar espaço no mercado, que era oWebWork. Ambas ascomunidadessefundiramedesenvolveramoStruts2,quevemaserumaversãomais simplesdesetrabalhardoqueoStruts1,ecomaindamaisrecursosefuncionalidades.

EditoraCasadoCódigocomlivrosdeumaformadiferente

11.2UMPOUCODEHISTÓRIA

11.2UMPOUCODEHISTÓRIA 147

Page 157: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Um dos frameworks mais famosos no mercado é o Spring MVC. Spring é um framework queinicialmentenãofoicriadoparaodesenvolvimentoweb.NaessênciaoSpringéumcontainerlevequevisafornecerserviçosparasuaaplicaçãocomoporexemploogerenciamentodeobjetosoutransação.Mas como tempo a comunidade Spring entendeu que o Struts era ultrapassado e começou criar umframeworkMVC próprio. O SpringMVC é um framework moderno que usa os recursos atuais dalinguagem além de usar todo poder do container Spring. Nesse capítulo veremos as funcionalidadesdesseframeworkpoderoso.

STRUTS1

Embora bastante antigo, o Struts 1 ainda é usado em muitas empresas. Os conceitos efundamentossãomuitoparecidosentreasversões,masaversãoantigaémaistrabalhosaepossuiformasparticularesdeuso.

STRUTS2

Apesardonomefamoso,oStruts2nuncafoitãoutilizadoquantooStruts1.EnquantooStruts1 erapioneirona época e se tornouopadrãonodesenvolvimentoweb Java, oStruts 2 eraumaescolhaentreváriosframeworksMVCqueofereciamasmesmasfacilidades.

ParaquepossamosaprenderoSpringMVC,vamoscriarumsistemadelistadetarefas.EoprimeiropassoqueprecisamosdaréteroSpringMVCparaadicionarmosemnossaaplicação.SpringMVCvemjuntocomasbibliotecasdo frameworkSpringquepodemosencontrarno sitehttps://spring.io/.Lá, épossívelencontrardiversasdocumentaçõesetutoriais,alémdosJARsdoprojeto.

Uma vez que adicionamos os JARs do SpringMVC em nosso projeto dentro do diretórioWEB-

INF/lib, precisamos declarar umServlet, que fará o papel deFrontController da nossa aplicação,

recebendoasrequisiçõeseasenviandoàslógicascorretas.ParadeclararmosaServletdoSpringMVC,bastaadicionarmosnoweb.xmldanossaaplicação:

<servlet><servlet-name>SpringMVCDispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>

11.3CONFIGURANDOOSPRINGMVC

148 11.3CONFIGURANDOOSPRINGMVC

Page 158: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

/WEB-INF/spring-context.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet>

<servlet-mapping><servlet-name>SpringMVCDispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

ReparequeéumaconfiguraçãonormaldeServlet,comservlet-classeurl-pattern,comoas

quefizemosantes.Temapenasumelementonovo,oinit-param.Esteparâmetroéumaconfiguração

quepodeserpassadaparaoservletpeloweb.xml.Aquidefinimosonomedoarquivodeconfiguração

do frameworkSpring,ospring-context.xml.QuandooServlet é carregado, elevaiprocurar esse

spring-context.xmldentrodapastaWEB-INF.

OframeworkSpringpossuisuaprópriaconfiguraçãoXML.OSpring,porsermuitomaisdoqueumcontroladorMVC,poderiaserutilizadoemambientesnãoWeb,ousejanemsempreoSpringpodesebasearnoweb.xml.Porestemotivo,masnãosomenteeste,oSpringdefiniuoseupróprioXMLcom

váriasopçõesparaconfiguraraaplicação.

A primeira coisa que faremos nesse arquivo é habilitar o uso de anotações do Spring MVC econfigurarpacotebasedaaplicaçãowebparaoSpringacharasnossasclasses:

<mvc:annotation-driven/><context:component-scanbase-package="br.com.caelum.tarefas"/>

Alémdisso,éprecisoinformaraoSpringolocalondecolocaremososarquivosJSP.ParaissoSpringMVC oferece uma classe especial que recebe o nome da pasta dos JSPs e a extensão dos arquivos.VamoscriartodososJSPsnapasta/WEB-INF/views/:

<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><propertyname="prefix"value="/WEB-INF/views/"/><propertyname="suffix"value=".jsp"/></bean>

IssojáésuficienteparacomeçarcomoSpringMVC.Oarquivocompleto,comtodososcabeçalhos,ficaentãocomo:

<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd

XMLespecíficodoSpring

11.3CONFIGURANDOOSPRINGMVC 149

Page 159: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scanbase-package="br.com.caelum.tarefas"/><mvc:annotation-driven/>

<beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><propertyname="prefix"value="/WEB-INF/views/"/><propertyname="suffix"value=".jsp"/></bean>

</beans>

No nosso framework MVC que desenvolvemos anteriormente, para criarmos nossas lógicas,criávamos uma classe que implementava uma interface. Existem diversas abordagens seguidas pelosframeworks para possibilitar a criação de lógicas. Passando por declaração em um arquivo XML,herdando de alguma classe do framework e, a partir do Java 5, surgiram as anotações, que são umaformadeintroduzirmetadadosdentrodenossasclasses.

OSpringMVCpermitecriaraslógicasdeformasdiferentes,usandoconvençõesoudeclarartudonoXML,porémnaversão3amaneiraindicadaéutilizandoanotações.

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

Paracriarmosnossaprimeiralógica,vamoscriarumaclassechamadaOlaMundoController.Nela

vamoscolocarmétodosquesãoasações(Action).OsufixoControllernãoéobrigatórioparao

Spring MVC porém é uma convenção do mercado. Como utilizaremos Spring MVC baseado emanotações,éobrigatórioqueoseuControllerestejadentrodopacotebr.com.caelum.tarefasouem um subpacote. No nosso caso, criaremos a classe dentro do pacote:

11.4CRIANDOASLÓGICAS

JáconheceoscursosonlineAlura?

11.5ALÓGICAOLÁMUNDO!

150 11.4CRIANDOASLÓGICAS

Page 160: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

br.com.caelum.tarefas.controller.

Dentro dessa nossa nova classe, vamos criar um método que imprimirá algo no console e, emseguida,iráredirecionarparaumJSPcomamensagem"Olámundo!".Aclassedeveseranotadacom@Controller,umaanotaçãodoSpringMVC.ElaindicaaoSpringqueosmétodosdessaclassesão

ações(Action).Podemoscriarummétododequalquernomedentrodessaclasse,desdequeeleesteja

com a anotação @RequestMapping. A anotação @RequestMapping recebe um atributo chamado

valuequeindicaqualseráaURLutilizadaparainvocarométodo,comoesseatributojáéopadrão

não precisamos definir. Portanto, se colocarmos o valor olaMundoSpring acessaremos o método

dentrodonosso@ControllerpelaURLhttp://localhost:8080/fj21-tarefas/olaMundoSpring.

Vamoschamarométodoexecute,masnovamentepoderiaserqualquernome.Essemétododeve

retornarumaString que indicaqual JSPdeve ser executadoapós a lógica.Por exemplo,podemos

retornar"ok"paraenviarousuárioparaumapáginachamadaok.jsp.Ométodonaodeveretornaro

sufixo da página, já que isso foi configurado noXML do Spring. Também lembrando que o SpringMVCprocuraaspáginasJSPdentrodapastaWEB-INF/views.

Dessaforma,teríamosaseguinteclasse:

@ControllerpublicclassOlaMundoController{

@RequestMapping("/olaMundoSpring")publicStringexecute(){System.out.println("ExecutandoalógicacomSpringMVC");return"ok";}}

Um ponto importante a se notar é que podemos criar outrosmétodos que respondam por outrasURL's,ouseja,váriosaçõesdentrodessaclasse(dentrodomesmo@Controller).Bastaria quenós

utilizássemosnovamenteaanotação@RequestMappingessesmétodos.

Porfim,sóprecisamoscriaroJSPquemostraráamensagem"Olámundo!".Bastacriaroarquivook.jspdentrodapastaWEB-INF/views/,quemapeamosanteriormentenoXMLdoSpring.

OJSPteráoseguinteconteúdo:

<html><body><h2>OlámundocomSpringMVC!</h2></body></html>

PodemosacessarnossométodopelaURLhttp://localhost:8080/fj21-tarefas/olaMundoSpring.OqueaconteceéqueapósaexecuçãodométodooSpringMVCverificaqualfoioresultadoretornadopeloseumétodoeprocuradespachararequisiçãoparaapáginaindicada.

11.5ALÓGICAOLÁMUNDO! 151

Page 161: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Caso você esteja em casa acesse a pasta21/projeto-tarefas e copie todos os arquivos das pastasmysql,logging,springframeworkeservletecoledentrodapastadoWEB-INF/libdeum

novoDynamicWebProject.Todososjarsnecessáriosestãolistadosaseguir:

commons-logging-1.x.jarjakarta.servlet-api-4.0.x.jarlog4j-1.2-api-2.13.x.jarmysql-connector-java-8.0.x.jarslf4j-api-2.0.x-alpha0.jarslf4j-log4j12-2.0.x-alpha0.jarspring-aop-5.x.x.RELEASE.jarspring-aspects-5.x.x.RELEASE.jarspring-beans-5.x.x.RELEASE.jarspring-context-5.x.x.RELEASE.jarspring-core-5.x.x.RELEASE.jarspring-expression-5.x.x.RELEASE.jarspring-jdbc-5.x.x.RELEASE.jarspring-web-5.x.x.RELEASE.jarspring-webmvc-5.x.x.RELEASE.jar

VocêtambémpodeoptarporseguiroexercícioaseguirnoqualcriaremosumnovoprojetodotipoDynamicWebProject e importaremos todas as dependências listadas acima através de um arquivocompactado.

1. VamosconfiguraroSpringMVCemumnovoprojeto.

Crieumnovoprojetoweb:File->New->Project...->DynamicWebProjectchamadofj21-tarefas.

NaabaServers,cliquecomobotãodireitonoTomcateváemAddandRemove...:

Bastaselecionaronossoprojetofj21-tarefaseclicaremAdd:

Vamoscomeçarimportandoasclassesqueserãonecessáriasaonossoprojeto,comoomodelodeTarefaseoDAO.

Cliquecomobotãodireitonoprojetofj21-tarefaseescolhaaopçãoImport.

11.6PARASABERMAIS:CONFIGURANDOOSPRINGMVCEMCASA

11.7EXERCÍCIOS:CONFIGURANDOOSPRINGMVCETESTANDOACONFIGURAÇÃO

152 11.6PARASABERMAIS:CONFIGURANDOOSPRINGMVCEMCASA

Page 162: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

SelecioneGeneral->ArchiveFile

Escolhaoarquivoprojeto-tarefas.zip que está em21/projeto-tarefas/ e confirme a

importação.

Abraoarquivoweb.xmlparafazermosadeclaraçãodoservletdoSpringMVC:

<servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring-context.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet>

<servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>

1. VamosfazerumsimplesOláMundo,paratestarmosnossaconfiguração:

2. Crie uma nova classe chamada OlaMundoController no pacotebr.com.caelum.tarefas.controller

3. Adicionenessaclasseoseguinteconteúdo:

@ControllerpublicclassOlaMundoController{

@RequestMapping("/olaMundoSpring")publicStringexecute(){System.out.println("ExecutandoalógicacomSpringMVC");return"ok";}}

Dica:UseCtrl+Shift+Oparaimportarasclasses.

4. Precisamos preparar a camada de visualização.Crie uma pastaviews para nossos JSPs que deveficardentrodapastaWebContent/WEB-INF.

5. Falta o JSP que será exibido após a execução da nossa lógica.Crie o JSPok.jsp no diretório

WebContent/WEB-INF/viewsdoprojetocomoconteúdo:

<html><body><h2>OlámundocomSpringMVC!</h2></body></html>

11.7EXERCÍCIOS:CONFIGURANDOOSPRINGMVCETESTANDOACONFIGURAÇÃO 153

Page 163: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

6. Reinicie o Tomcat e acesse no seu navegador o endereço http://localhost:8080/fj21-

tarefas/olaMundoSpring.Oresultadodeveseralgoparecidocom:

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

Vamos começar a criar o nosso sistema de tarefas.Guardaremos uma descrição da tarefa, e umaindicação informando se a tarefa já foi finalizada ou não e quando foi finalizada. Esse sistema écompostopeloseguintemodelo:

publicclassTarefa{privateLongid;privateStringdescricao;privatebooleanfinalizado;privateCalendardataFinalizacao;

//gettersesetters

VocêpodetambémfazerocursodatadessaapostilanaCaelum

11.8ADICIONANDOTAREFASEPASSANDOPARÂMETROS

154 11.8ADICIONANDOTAREFASEPASSANDOPARÂMETROS

Page 164: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

Vamoscriarafuncionalidadedeadiçãodenovastarefas.Paraisso,teremosumatelacontendoumformuláriocomcamposparaserempreenchidos.Queremosque,aocriarmosumanovatarefa,amesmavenhaporpadrãocomonãofinalizadae,consequentemente,semadatadefinalizaçãodefinida.Dessaforma, nosso formulário terá apenas o campo descricao . Podemos criar um JSP chamado

formulario.jspcontendosomenteocampoparadescrição:

<html><body><h3>Adicionartarefas</h3><formaction="adicionaTarefa"method="post">Descrição:<br/><textareaname="descricao"rows="5"cols="100"></textarea><br/>

<inputtype="submit"value="Adicionar"></form></body></html>

Onosso form, ao ser submetido, chamaumaação,ummétododentrodeum@Controller que

respondepelaURLadicionaTarefa.Essemétodoprecisareceberosdadosdarequisiçãoegravara

tarefaqueousuárioinformounatela.Vamoschamaressemétodoadicionaecolocardentrodaclasse

TarefasController:

@ControllerpublicclassTarefasController{

@RequestMapping("adicionaTarefa")publicStringadiciona(){JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa-adicionada";}}

Mas,comomontaremosoobjetotarefaparapassarmosaonossoDAO?Dentrodessanossaclasse

TarefasController em nenhum momento temos um HttpServletRequest para pegarmos os

parâmetrosenviadosnarequisiçãoemontarmosoobjetotarefa.

Uma das grandes vantagens de frameworksmodernos é que eles conseguempopular os objetosparanós.Bastaquedealgumaforma,nósfaçamosumaligaçãoentreocampoqueestánatelacomoobjetoquequeremospopular.EcomoSpringMVCnãoédiferente.

Essaligaçãoéfeitaatravésdacriaçãodeumparâmetrodométodoadiciona.Esseparâmetroéo

objeto que deverá ser populadopeloSpringMVCcomos dados que vieramda requisição. Portanto,vamoscriarnonossométodoumnovoparâmetrochamadotarefa:

@ControllerpublicclassTarefasController{

@RequestMapping("adicionaTarefa")

11.8ADICIONANDOTAREFASEPASSANDOPARÂMETROS 155

Page 165: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicStringadiciona(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa-adicionada";}}

Queremosqueocampodetextoquecriamosnonossoformuláriopreenchaadescriçãodessatarefa.Parafazermosisso,bastadarmosonomecomocaminhodapropriedadequequeremosdefinir.Portanto,sedentrodoobjetotarefaqueremosdefinirapropriedadedescricao,bastanomearmosoinput

comdescricao.OSpringMVCcriaoobjetotarefaparanósepreencheesseobjetocomosdados

darequisição,nessecasocomoparâmetrodescricaodarequisição.ComoaclasseTarefa é um

JavaBeanepossuiconstrutorsemargumentosegetters/settersissonãoseráproblema.

Por fim, basta exibirmos a mensagem de confirmação de que a criação da tarefa foi feita comsucesso.Criamosoarquivotarefa-adicionada.jspcomoseguinteconteúdoHTML:

<html><body>Novatarefaadicionadacomsucesso!</body></html>

Anossaaplicaçãoteráváriaspáginasrelacionadascomumaoumaistarefas.Queremosorganizaranossa aplicaçãodesde início e separaros arquivos JSPs relacionadas em subpastas.Ou seja, todas aspáginasJSPrelacionadascomomodelotarefaficarãonapastatarefa.Porisso,vamoscriarumanova

pastatarefadentrodapastaWEB-INF/viewsparaosJSPsqueoTarefasControllervaiusar.Por

padrão,oSpringMVCnãoprocura emsubpastas, procura apenasnapastaviews.Vamosmudar o

retornodométodoadicionaedevolveronomedasubpastaeonomedapáginaJSP.Nessecasoo

retornoficacomotarefa/adicionada.

Portanto,ocódigocompletodométodoadicionafica:

@ControllerpublicclassTarefasController{

@RequestMapping("adicionaTarefa")publicStringadiciona(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";}}

Na pasta WEB-INF/views/tarefa também deve ficar o formulário para adicionar uma tarefa.

Como discutimos antes, todos os JSPs da tarefa na mesma subpasta. Porém aqui surge um novoproblema:ÉprecisocarregaroJSPnonavegador,masoacessodiretoaopastaWEB-INF é proibido

MelhoraraorganizaçãodosarquivosJSPs

156 11.8ADICIONANDOTAREFASEPASSANDOPARÂMETROS

Page 166: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

peloservlet-containereconsequentementenãoépossívelacessaroformulário.Pararesolverissovamoscriarumanovaação(umnovométodo)dentrodaclasseTarefasControllerquetemafinalidadede

chamar o formulário apenas. O método usa também a anotação @RequestMappping e retorna um

Stringparachamaroformulário.

AbaixoocódigocompletodoTarefasControllercomosdoismétodos:

@ControllerpublicclassTarefasController{

@RequestMapping("novaTarefa")publicStringform(){return"tarefa/formulario";}

@RequestMapping("adicionaTarefa")publicStringadiciona(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";}}

AestruturadaspastaWEB-INFficacomo:

WEB-INF-views-tarefa-formulario.jsp-adicionada.jsp

ParachamaroformuláriousaremosaURL:http://localhost:8080/fj21-tarefas/novaTarefa

Vamoscriaroformulárioenossaaçãoparafazeragravaçãodastarefas.

1. Oprimeiropassoécriarnossoformulárioparaadicionarumatarefa.ParaissocrieumapastatarefadentrodapastaWebContent/WEB-INF/views.Dentrodapasta tarefa adicioneumnovo arquivoformulario.jsp.

<html><body><h3>Adicionartarefas</h3><formaction="adicionaTarefa"method="post">Descrição:<br/><textareaname="descricao"rows="5"cols="100"></textarea><br/><inputtype="submit"value="Adicionar"></form></body></html>

1. Agoraprecisamosummétodo(action)dentrodeum@Controller paraacessaro JSP.Crieuma

11.9EXERCÍCIOS:CRIANDOTAREFAS

11.9EXERCÍCIOS:CRIANDOTAREFAS 157

Page 167: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

novaclassenopacotebr.com.caelum.tarefas.controllerchamadaTarefasController.

Nossaclasseprecisa terummétodoparaacessaro JSP.Vamoschamarométodo form()eusaraanotação@RequestMapping:

@ControllerpublicclassTarefasController{

@RequestMapping("novaTarefa")publicStringform(){return"tarefa/formulario";}

}

UseCtrl+Shift+Oparaimportarasclasses.

2. Aindafaltaométodoquerealmenteadicionaatarefanobancodedados.Essemétodoéchamadopelo nosso formulário e recebe uma tarefa como parâmetro. Ele novamente usa a anotação@RequestMappingparadefiniraURL.

DentrodaclasseTarefasControllercrieométodoadicionaquerecebeumatarefa.Nométodo

usamosaJdbcTarefaDaoparapersistirosdados.Oretornodométododefineolocalenomedo

JSP.

Ocódigodeveficar:

@RequestMapping("adicionaTarefa")publicStringadiciona(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";}

3. E, por fim, criamos o arquivo adicionada.jsp na pasta tarefa que mostrará uma mensagem deconfirmaçãodequeatarefafoiefetivamenteadicionada.

<html><body>Novatarefaadicionadacomsucesso!</body></html>

1. ReinicieoTomcat.

Acesse no seu navegador o endereço http://localhost:8080/fj21-tarefas/novaTarefa e

adicioneumanovatarefa.

158 11.9EXERCÍCIOS:CRIANDOTAREFAS

Page 168: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Casoaconteçaumaexceção informandoquea tabelanãoestácriada,crie-acomoscriptabaixoetenteinserirnovamenteatarefa.Abraoterminaledigite:

mysql-uroot

Lembrandoque,sehouversenhaparalogarcomobanco,éprecisoescrevermysql-uroot-pe,

emseguida,digitarasenhadobancodedados.

DentrodoMySQL,digite:

usefj21;

Emseguida,digite:

createtabletarefas(idBIGINTNOTNULLAUTO_INCREMENT,descricaoVARCHAR(255),finalizadoBOOLEAN,dataFinalizacaoDATE,primarykey(id));

(Dica: todo código usado para crição da estrutura do banco de dados encontra-se no arquivocriacao-tabelas.sqlnapasta21/projeto-tarefas/mysql)

11.9EXERCÍCIOS:CRIANDOTAREFAS 159

Page 169: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Já conseguimos adicionar novas tarefas emnossa aplicação. Porém, o que impede algumusuáriodesatento incluiruma tarefa semdescrição?Atéagora,nada.Nósqueremosqueumusuárionão sejacapaz de adicionar uma tarefa sem descrição, para isso precisamos incluir algum mecanismo devalidaçãoemnossaaçãodeadicionartarefas.Avalidaçãodeveserexecutadanoladodoservidor,afimdegarantirqueosdadosserãovalidadosemumlugarondeousuárionãoconsigainterferir.

A maneira mais fácil de validar a tarefa é usar vários ifs no método adiciona da classe

TarefasController antes de chamar dao.adiciona(tarefa) , executando a validação

programaticamente.Ocódigoseguintemostraaideia:

@RequestMapping("adicionaTarefa")publicStringadiciona(Tarefatarefa){

if(tarefa.getDescricao()==null||tarefa.getDescricao().equals("")){return"tarefa/formulario";}

JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";}

O problema aqui é quantomais atributos na tarefamais ifs teremos. É provável também que

vamosrepetirumifououtroquandovalidarmosatarefaemmétodosdiferentes,porexemplo,para

adicionaroualteraratarefa.Sabemosquecopiarecolarcódigonãoéumaboamaneiradereaproveitarcódigo.Oqueprecisamosédealgumartifícioquesejaigualparaqualquermétodo,algoqueajudenavalidaçãodosdados.

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

11.10INCLUINDOVALIDAÇÃONOCADASTRODETAREFAS

Validandoprogramaticamente

Seuslivrosdetecnologiaparecemdoséculopassado?

160 11.10INCLUINDOVALIDAÇÃONOCADASTRODETAREFAS

Page 170: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

A partir do Java EE 6 temos uma especificação que resolve este problema.A JSR 303, tambémconhecidacomoBeanValidation,defineumasériedeanotaçõeseumaAPIparacriaçãodevalidaçõesparaseremutilizadasemJavaBeans,quepodemservalidadosagoraemqualquercamadadaaplicação.

Com o BeanValidation declaramos através de anotações as regras de validação dentro do nossomodelo,porexemplo,nanossatarefa:

publicclassTarefa{

privateLongid;

@Size(min=5)privateStringdescricao;

privatebooleanfinalizado;privateCalendardataFinalizacao;

//...}

Pronto!Comessas anotações, qualquer objeto do tipoTarefa pode ser validado na camada de

controller.SófaltaavisaroSpringMVCquerealmentequeremosexecutaravalidação.IssoéfeitopelaanotaçãoValidquedevemosusarnaantesdoparâmetrodaação:

@RequestMapping("adicionaTarefa")publicStringadiciona(@ValidTarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";}

ComoestamosfalandodeSpringMVC,antesdachamadadométodoéexecutadaavalidação,ousejaseráverificadoseadescriçãodatarefanãoestávazia.Seestiver,serálançadaumaexceçãodotipoConstraintViolationExceptionquepossuiadescriçãodoerro.

Não queremos mostrar uma exceção para o usuário e sim apenas voltar para o formulário paramostrarumamensagemqueavalidaçãofalhou.OSpringMVCpodeguardaroresultado(oserrosdevalidação)emumobjetodo tipoBindingResult.Assimnão será lançadoumexceção.Este objeto

BindingResultsetornaumparâmetrodaação.Entãosóéprecisoperguntarparaeleseexisteumerro

devalidaçãoeseexistir,voltarparaoformulário.Vejaocódigo:

@RequestMapping("adicionaTarefa")publicStringadiciona(@ValidTarefatarefa,BindingResultresult){

if(result.hasFieldErrors("descricao")){return"tarefa/formulario";}

JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";

11.11VALIDAÇÃOCOMBEANVALIDATION

11.11VALIDAÇÃOCOMBEANVALIDATION 161

Page 171: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

Nocódigoacimaverificamosseexisteumdeerrovalidaçãorelacionadocomoatributodescricao

datarefa.Tambémpodemosconferirseexistealgumerrodevalidação,maisgenérico:

@RequestMapping("adicionaTarefa")publicStringadiciona(@ValidTarefatarefa,BindingResultresult){

if(result.hasErrors()){return"tarefa/formulario";}//...}

ParaexibirasmensagensdevalidaçãonoJSPusamosumtagespecialqueoSpringMVCoferece.Otagsechamaform:errors:

<form:errorspath="tarefa.descricao"/>

Oatributopathindicacomqueatributoessamensagemestárelacionada.

Abaixoestáocódigocompletodoformulárioformulario.jspdapastatarefa.Reparequeépreciso

importarotaglibdoSpringMVC:

<%@tagliburi="http://www.springframework.org/tags/form"prefix="form"%><html><body><h3>Adicionartarefas</h3><formaction="adicionaTarefa"method="post">Descrição:<br/><textarearows="5"cols="100"name="descricao"></textarea><br/><form:errorspath="tarefa.descricao"cssStyle="color:red"/><br/><inputtype="submit"value="Adicionar"/></form></body></html>

Para deixar as mensagens de nossa aplicação mais fáceis de alterar, é comum criar um arquivoseparado do HTML que possui apenas mensagens. Este arquivo é normalmente chamadomensagens.propertiesoumessages.properties.

NapastaWEB-INFdoprojetopodemosentãocriarestearquivocomoseguinteconteúdo:

tarefa.adicionada.com.sucesso=Tarefaadicionadacomsucesso!...

Reparequedefinimosasmensagensemumestilode:<chave>=<valor>.

Mostrandoasmensagensdevalidação

Mensagensinternacionalizadas

162 11.11VALIDAÇÃOCOMBEANVALIDATION

Page 172: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

OSpringMVCpodecarregarautomaticamenteestearquivo,desdequealinhaabaixosejaincluídanoarquivospring-context.xml:

<beanid="messageSource"class="org.springframework.context.support.ReloadableResourceBundleMessageSource"><propertyname="basename"value="/WEB-INF/mensagens"/></bean>

Basta então usar a taglibfmt paramostramensagens do arquivo mensagens.properties na

páginaHTML:

<fmt:messagekey="tarefa.adicionada.com.sucesso"/>

Podemos ainda personalizar as mensagens de validação do Bean Validation, escrevendo nossasmensagensdentrodoatributomessagedasanotações:

publicclassTarefa{

privateLongid;

@Size(min=5,message="Descriçãodeveterpelomenos5carateres")privateStringdescricao;//...}

Para não deixar as mensagens de validação espalhadas em nossas classes, podemos isolar estasmensagens no arquivo padrão de mensagens do Bean Validation, chamadoValidationMessages.properties:

tarefa.descricao.pequena=Descriçãodeveconterpelomenos{min}caracteres...

O arquivo deve ficar dentro da pasta src. Depois podemos referenciar as chaves das mensagensdentrodasanotaçõestambémpeloatributomessage:

publicclassTarefa{

privateLongid;

@Size(min=5,message="{tarefa.descricao.pequena}")privateStringdescricao;}

1. ParaconfiguraroframeworkBeanValidationéprecisocopiarcincojars.

Primeiro, acesse a pasta do arquivos do curso, mais específicamente 21/projeto-tarefas/validator.

Personalizandoasmensagensdeerros

11.12EXERCÍCIOS:VALIDANDOTAREFAS

11.12EXERCÍCIOS:VALIDANDOTAREFAS 163

Page 173: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

HaverácincoJARs:

classmate-1.3.X.jarhibernate-validator-6.1.X.Final.jarjakarta.el-3.0.X.jarjakarta.validation-api-2.0.X.jarjboss-logging-3.3.X.Final.jar

Copie-os (CTRL+C) e cole-os (CTRL+V) dentro do workspace do eclipse na pasta fj21-tarefas/WebContent/WEB-INF/lib

2. Abra a classe Tarefa. Nela é preciso definir as regras de validação através das anotações do

frameworkBeanvalidation.Aatributodescricaodeveterpelomenos5caracteres:

publicclassTarefa{

privateLongid;

@Size(min=5)privateStringdescricao;

1. AbraaclasseTarefasControllereprocureométodoadiciona.Coloqueaanotação@Valid

nafrentedoparâmetroTarefatarefaeadicioneoparâmetroBindingResultnaassinaturado

método.

Alémdisso,nomesmométodo,adicioneaverificaçãoseháerrosdevalidação.Ométodocompletofica:

@RequestMapping("adicionaTarefa")publicStringadiciona(@ValidTarefatarefa,BindingResultresult){

if(result.hasFieldErrors("descricao")){return"tarefa/formulario";}

JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";}

1. AbraoJSPformulario.jsp(dapastaWEB-INF/views/tarefa).Adicionenoiníciodapáginaa

declaraçãodataglibdoSpringMVC:

<%@tagliburi="http://www.springframework.org/tags/form"prefix="form"%>

DentrodoHTMLadicioneapenastagform:errorsacimadotagform:

<form:errorspath="tarefa.descricao"/><formaction="adicionaTarefa"method="post">

1. Reinicie o Tomcat e acesse no seu navegador o endereço http://localhost:8080/fj21-

164 11.12EXERCÍCIOS:VALIDANDOTAREFAS

Page 174: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

tarefas/novaTarefaEnvieumarequisiçãoSEMpreencheradescriçãodatarefa,amensagemde

validaçãodeveaparecer.

Comojáconseguimosadicionartarefasemnossaaplicação,precisamossaberoquefoiadicionado.Para isso precisamos criar uma nova funcionalidade que lista as tarefas. A função dessa ação seráinvocaroJdbcTarefaDao para conseguir a listadas tarefasque estãonobancodedados.Podemos

adicionarumnovométododentrodaclasseTarefasController:

@RequestMapping("listaTarefas")publicStringlista(){JdbcTarefaDaodao=newJdbcTarefaDao();List<Tarefa>tarefas=dao.lista();return"tarefa/lista";}

Essa lista de tarefas deverá ser disponibilizadapara o JSP fazer sua exibição.Para quepossamosdisponibilizarumobjetoparao JSP, temosquealteraro retornodométodolista.A ideia é queo

SpringMVCnãosórecebeonomedapáginaJSP(tarefa/lista)quandochamaométodolista,o

SpringMVCtambémrecebeosdadosparaoJSP.OsdadosparaaexibiçãonatelaeonomedapáginaJSP foram encapsulados pelo SpringMVC em uma classe especial que se chama ModelAndView.

VamoscriarumobjetodotipoModelAndView epreencheressemodelocomnossa listade tarefase

definir o nome da página JSP. O método lista deve retornar esse objeto, não mais apenas um

String.Vejacomoficaocódigo:

@RequestMapping("listaTarefas")

11.13LISTANDOASTAREFASEDISPONIBILIZANDOOBJETOSPARAAVIEW

11.13LISTANDOASTAREFASEDISPONIBILIZANDOOBJETOSPARAAVIEW 165

Page 175: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicModelAndViewlista(){JdbcTarefaDaodao=newJdbcTarefaDao();List<Tarefa>tarefas=dao.lista();

ModelAndViewmv=newModelAndView("tarefa/lista");mv.addObject("tarefas",tarefas);returnmv;}

Dessaforma,serádisponibilizadoparaoJSPumobjetochamadotarefasquepodeseracessado

viaExpressionLanguagecomo${tarefas}.Poderíamosemseguidaiterarsobreessalistautilizandoa

TagforEachdaJSTLcore.

VendoocódigodaaçãolistapodeaparecerestranhoinstanciarumaclassedoframeworkSpring

(ModelAndView) dentro do nosso controlador. Isso até influencia negativamente a testabilidade do

método. Por isso, O Spring MVC dá uma outra opção, oferece uma alternativa ao uso da classeModelAndView.NanossaaçãopodemosreceberumobjetoquerepresentaomodeloparaonossoJSP.

SpringMVCpodepassar umparâmetropara ométododo controlador que tema funçãodomodelo.Essemodelo podemos preencher com a lista de tarefas.Assim também continuaremos devolver umaStringcomoretornodométodoqueindicaocaminhoparaoJSP:

@RequestMapping("listaTarefas")publicStringlista(Modelmodel){JdbcTarefaDaodao=newJdbcTarefaDao();List<Tarefa>tarefas=dao.lista();model.addAttribute("tarefas",tarefas);return"tarefa/lista";}

Dessamaneiranãoéprecisoinstanciaromodelo,esimapenasdisponibilizaralista.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

1. Vamoscriaralistagemdasnossastarefasmostrandoseamesmajáfoifinalizadaounão.

Agoraéamelhorhoradeaprenderalgonovo

11.14EXERCÍCIOS:LISTANDOTAREFAS

166 11.14EXERCÍCIOS:LISTANDOTAREFAS

Page 176: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Na classe TarefasController adicione o método lista que recebe um Model como

parâmetro:

@RequestMapping("listaTarefas")publicStringlista(Modelmodel){JdbcTarefaDaodao=newJdbcTarefaDao();model.addAttribute("tarefas",dao.lista());return"tarefa/lista";}

Parafazeralistagem,vamosprecisardaJSTL(iremosfazerumforEach),portantoprecisamos

importá-la.Primeiro,entrenodiretóriodosarquivosdocursoedepoisem21/projeto-tarefas/jstl.

HaverãodoisJARs:

jakarta.servlet.jsp.jstl-1.2.x.jarjakarta.servlet.jsp.jstl-api-1.2.x.jar.

Copie-os (CTRL+C) e cole-os (CTRL+V) dentro do workspace do eclipse na pasta fj21-tarefas/WebContent/WEB-INF/lib

NoEclipse,dêumF5noseuprojeto.Pronto,aJSTLjáestáemnossoprojeto.

CrieoJSPquefaráaexibiçãodastarefasdentrodapastaWebContent/WEB-INF/views/tarefa.

Chame-odelista.jspeadicioneoseguinteconteúdo:

<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><%@tagliburi="http://java.sun.com/jsp/jstl/fmt"prefix="fmt"%><html><body>

<ahref="novaTarefa">Criarnovatarefa</a>

<br/><br/>

<table><tr><th>Id</th><th>Descrição</th><th>Finalizado?</th><th>Datadefinalização</th></tr><c:forEachitems="${tarefas}"var="tarefa"><tr><td>${tarefa.id}</td><td>${tarefa.descricao}</td><c:iftest="${tarefa.finalizadoeqfalse}"><td>Nãofinalizado</td></c:if><c:iftest="${tarefa.finalizadoeqtrue}"><td>Finalizado</td></c:if><td><fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/>

11.14EXERCÍCIOS:LISTANDOTAREFAS 167

Page 177: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

</td></tr></c:forEach></table></body></html>

Reinicie o Tomcat e acesse o endereço http://localhost:8080/fj21-tarefas/listaTarefas e veja oresultado.

Tarefas podem ser adicionadas por engano, ou pode ser que não precisemosmais dela, portanto,queremos removê-las. Para fazer essa remoção, criaremos um link na listagem que acabamos dedesenvolverque,aoserclicado,invocaráanovaaçãoparaaremoçãodetarefaspassandoocódigodatarefaparaserremovida.

OlinkpodeserfeitocomHTMLnalistadetarefasdaseguinteforma:

<td><ahref="removeTarefa?id=${tarefa.id}">Remover</a></td>

Podemos desenvolver ummétodo para fazer a remoção.A lógica não possui nenhuma novidade,basta recuperarmosoparâmetro comoaprendemosnesse capítulo e invocarmosoDAO para fazer a

remoção:

@RequestMapping("removeTarefa")publicStringremove(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.remove(tarefa);return"paraondeir???";}

Aquestãoé:Paraquallugarredirecionarousuárioapósaexclusão?

PoderíamoscriarumnovoJSPcomumamensagemdeconfirmaçãoda remoção,masusualmenteisso não costuma ser bom, porque precisaríamos navegar até a lista das tarefas novamente casotenhamos que remover outra tarefa. Seria muito mais agradável para o usuário que ele fosseredirecionadodiretoparaalistadastarefas.

11.15REDIRECIONANDOAREQUISIÇÃOPARAOUTRAAÇÃO

168 11.15REDIRECIONANDOAREQUISIÇÃOPARAOUTRAAÇÃO

Page 178: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Umadasformasquepoderíamosfazeresseredirecionamentoéenviarousuáriodiretamenteparaapágina que lista as tarefas (tarefa/lista.jsp). Mas, essa não é uma boa abordagem, porque

precisaríamos,outravez,disponibilizara listadas tarefasparaoJSP,algoque já fazemosnaaçãodelistarastarefas,ométodolistanaclasseTarefasController.

Jáqueométodolistafazessetrabalho,poderíamos,aoinvésderedirecionaraexecuçãoparao

JSP, enviá-la para essa ação. Para isso, o retorno dométodo deve ser um poucomodificado.VamoscontinuardevolvendoumaStringmasessaStringdeve indicarquequeremoschamarumaoutra

ação.Podemosfazerumredirecionamentonaladodoservidor(forward)oupelonavegador,noladodocliente(redirect).

Parafazerumredirecionamentonoladodoservidorbastausaroprefixoforwardnoretorno:

@RequestMapping("removeTarefa")publicStringremove(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.remove(tarefa);return"forward:listaTarefas";}

Parafazerumredirecionamentonoladodoclienteusamosoprefixoredirect:

@RequestMapping("removeTarefa")publicStringremove(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.remove(tarefa);return"redirect:listaTarefas";}

1. Vamosfazerafuncionalidadederemoçãodetarefas.

Adicionenoarquivolista.jspumacolunacomumlinkqueaoserclicadoinvocaráaAction

pararemovertarefa.

<td><ahref="removeTarefa?id=${tarefa.id}">Remover</a></td>

CrieumnovométodoremovenaclasseTarefasControllercomocódigo:

@RequestMapping("removeTarefa")publicStringremove(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.remove(tarefa);return"redirect:listaTarefas";}

Acesse a lista de tarefas em http://localhost:8080/fj21-tarefas/listaTarefas e remova algumastarefas.

1. Criaremos a tela para fazer a alteração das tarefas, como por exemplo, marcá-la como

11.16EXERCÍCIOS:REMOVENDOEALTERANDOTAREFAS

11.16EXERCÍCIOS:REMOVENDOEALTERANDOTAREFAS 169

Page 179: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

finalizadaedefinirmosadatadefinalização.

Primeirovamoscriarumnovolinknanossalistagemqueenviaráousuárioparaatelacontendoosdadosdatarefaselecionada:

<td><ahref="mostraTarefa?id=${tarefa.id}">Alterar</a></td>

Vamoscriarumanovaaçãoquedadoumid,devolveráaTarefacorrespondenteparaumJSP,

quemostraráosdadosparaqueaalteraçãopossaserfeita.

CrieumnovométodomostranaclasseTarefasController:

@RequestMapping("mostraTarefa")publicStringmostra(Longid,Modelmodel){JdbcTarefaDaodao=newJdbcTarefaDao();model.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/mostra";}

CrieoJSPmostra.jspdentrodapastaviews/tarefaparamostraratarefaescolhida:

<%@taglibprefix="fmt"uri="http://java.sun.com/jsp/jstl/fmt"%>

<html><body><h3>Alterartarefa-${tarefa.id}</h3><formaction="alteraTarefa"method="post">

<inputtype="hidden"name="id"value="${tarefa.id}"/>

Descrição:<br/><textareaname="descricao"cols="100"rows="5">${tarefa.descricao}</textarea><br/>

Finalizado?<inputtype="checkbox"name="finalizado"value="true"${tarefa.finalizado?'checked':''}/><br/>

Datadefinalização:<br/><inputtype="text"name="dataFinalizacao"value="<fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/>"/><br/>

<inputtype="submit"value="Alterar"/>

</form></body></html>

Para o Spring MVC saber converter automaticamente a data no formato brasileiro para umCalendar é precisousar a anotaçã[email protected] a classeTarefa e adicione a

anotaçãoacimadoatributodataFinalizacao:

@DateTimeFormat(pattern="dd/MM/yyyy")

170 11.16EXERCÍCIOS:REMOVENDOEALTERANDOTAREFAS

Page 180: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

privateCalendardataFinalizacao;

Faltacriarummétodoquecuidarádaalteraçãodatarefa.NaclasseTarefasControlleradicione

essemétodo:

@RequestMapping("alteraTarefa")publicStringaltera(Tarefatarefa){JdbcTarefaDaodao=newJdbcTarefaDao();dao.altera(tarefa);return"redirect:listaTarefas";}

Acessealistadetarefasemhttp://localhost:8080/fj21-tarefas/listaTarefasealterealgumastarefas.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

1. AdicioneocampocomcalendárioquefizemosnocapítulodecriaçãodeTagsemnossoprojetoeutilize-onoformuláriodealteração.

Sempre que precisamos finalizar uma tarefa, precisamos entrar na tela de alteração da tarefa quequeremoseescolheradatadefinalização.Essadatadefinalizaçãonamaioriadasvezeséaprópriadataatual.

Para facilitar a usabilidade para o usuário, vamos adicionar umnovo link na nossa tabela que sechamará"Finalizaragora".Aoclicarnesselink,umaaçãoseráinvocadaparafinalizarmosatarefanodiaatual.

A questão é que não queremos navegar para lugar algum ao clicarmos nesse link. Queremospermanecernamesmatela,semquenadaaconteça,nemsejarecarregado.

EditoraCasadoCódigocomlivrosdeumaformadiferente

11.17DESAFIO-CALENDÁRIO

11.18MELHORANDOAUSABILIDADEDANOSSAAPLICAÇÃO

11.17DESAFIO-CALENDÁRIO 171

Page 181: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Ouseja,dealgumaformaprecisamosmandararequisiçãoparaaação,masaindaassimprecisamosmanter apáginado jeitoqueela estavaaoclicarno link.Podemos fazer isso atravésdeuma técnicachamadaAJAX,quesignificaAsynchronousJavascriptandXML.

AJAX nadamais é do que uma técnica que nos permite enviar requisições assíncronas, ou seja,manter a página que estava aberta intacta, e recuperar a resposta dessa requisição para fazermosqualquer processamento com eles. Essas respostas costumam ser XML, HTML ou um formato detransferênciadedadoschamadoJSON(JavascriptObjectNotation).

PararealizarmosumarequisiçãoAJAX,precisamosutilizarJavascript.EnocursovamosutilizarosuportequeojQuerynosforneceparatrabalharcomAJAX.

ParafazermosumarequisiçãoparaumdeterminadoendereçocomojQuery,bastadefinirmosqualmétodoutilizaremosparaenviaressarequisição(POSTouGET).OjQuerynosforneceduasfunções:$.poste$.get,cadaumaparacadamétodo.

Paraasfunçõesbastapassarmosoendereçoquequeremosinvocar,comoporexemplo:

$.get("minhaPagina.jsp")

Nessecaso,estamosenviandoumarequisiçãoviaGETparaoendereçominhaPagina.jsp.

Sabendoisso,vamoscriarumlinkqueinvocaráumafunçãoJavascriptefarárequisiçãoAJAXparaumaaçãoquefinalizaráatarefa:

<td><ahref="#"onclick="finalizaAgora(${tarefa.id})">Finalizaragora</a></td>

Vamos criar a funçãofinalizaAgora que recebe o id da tarefa que será finalizada e a passará

comoparâmetroparaaação:

<scripttype="text/javascript">functionfinalizaAgora(id){$.get("finalizaTarefa?id="+id);}</script>

Por fim, basta criarmos a nossa ação que receberá o parâmetro e invocará um método doJdbcTarefaDaoparafazerafinalizaçãodatarefa.Noentanto,arequisiçãoqueestamosfazendonão

gerarárespostanenhumaenóssempreretornamosumaStringoresultadoquedeterminaqualJSPseráexibido.Dessavez,nãoexibiremosnemumJSPeneminvocaremosoutraAction.OprotocoloHTTP

sempre retorna um código indicando qual é o estado dessa resposta, ou seja, se foi executado comsucesso,seapáginanãofoiencontrada,sealgumerroaconteceueassimpordiante.

OprotocoloHTTPdefinequeocódigo200indicaqueaexecuçãoocorreucomsucesso,portanto,vamosapenasindicarnanossarespostaocódigo,semdevolvernadanocorpodanossaresposta.Para

172 11.18MELHORANDOAUSABILIDADEDANOSSAAPLICAÇÃO

Page 182: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

setarocódigodarespostaprogramaticamenteprecisamosdoobjetoHttpServletResponse.PodemosreceberarespostaHTTPcomoparâmetrodequalquermétodoqueéumaação.ComarespostanamãopodemoschamarométodosetStatus(200).

Dessaforma,poderíamosterummétodonaclasseTarefasControllerparafazerafinalizaçãoda

tarefacomoseguintecódigo:

@RequestMapping("finalizaTarefa")publicvoidfinaliza(Longid,HttpServletResponseresponse){JdbcTarefaDaodao=newJdbcTarefaDao();dao.finaliza(id);response.setStatus(200);}

Oprimeiroparâmetroéa idda tarefaquevematravésdarequisição,osegundoéa respostaparasetarocódigoHTTP.

Quando estamos usando um Framework MVC como o Spring, queremos que toda a parte demanipulaçãoderequesteresponsefiqueporcontadoframework.Daformaquemostramosantesé

possível obter o resultado que esperamos,masmanipular o status da resposta é uma tarefa que nãoqueremos fazer diretamente. O Spring nos ajuda nessa tarefa, fazendo com que o retorno do nossométodosejaHTTP200,excetoemcasodealgumaexception.Paraisso,[email protected]óprionomeda annotation fala, tudoque for retornado, será o

corpodanossaresposta.Ousenadaforretornado,entãoarespostaserávaziaporémostatusHTTPserá200.Nossocódigopodeficarmaisenxutoesemamanipulaçãodoresponse:

@ResponseBody@RequestMapping("finalizaTarefa")publicvoidfinaliza(Longid){JdbcTarefaDaodao=newJdbcTarefaDao();dao.finaliza(id);}

Através do jQuery, podemos enviar uma requisição AJAX para o servidor, e na ação vamosmanipulararespostaesetarapenasostatus200.Tambémseriaútilnotificarousuáriodaaplicaçãoquearequisiçãofinalizoucomsucesso.OjQueryjáforneceumjeitomuitosimplesdeimplementarisso.ÉprecisoadicionarnoJavaScriptumafunçãoqueéchamadaquandoa requisição terminacomsucesso(status200).

<scripttype="text/javascript">functionfinalizaAgora(id){$.get("finalizaTarefa?id="+id,function(dadosDeResposta){alert("TarefaFinalizada!");});}</script>

11.19 UTILIZANDO AJAX PARA MARCAR TAREFAS COMOFINALIZADAS

11.19UTILIZANDOAJAXPARAMARCARTAREFASCOMOFINALIZADAS 173

Page 183: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Repare que $.get recebe mais uma função como parâmetro (também chamado callback de

sucesso).Nela,definimosapenasumsimplesalertparamostrarumamensagemaousuário.TambémépossívelmanipularoHTMLdapáginadinamicamente.OjQueryoferecerecursospoderososparaalterarqualquerelementoHTMLdentrodonavegador.

Por exemplo, podemos selecionar um elemento da página pela id e mudar o conteúdo desse

elemento:

$("#idDoElementoHTML").html("NovoconteúdoHTMLdesseelemento");

Para o nosso exemplo, então é interessante atualizar a coluna da tarefa para indicar que ela foifinalizada:

$("#tarefa_"+id).html("Tarefafinalizada");

LeiamaissobreojQuerynadocumentação:

http://api.jquery.com/jQuery.get/http://api.jquery.com/id-selector/

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

OcontroladordoSpringMVC,ousejaoservletnoweb.xml,foiconfiguradopararecebertodasasrequisições incluindo essas que foram enviadas para receber o conteúdo de arquivos comuns comoimagens, css ou scripts. Queremos que o controlador não atenda essas requisições que não são paraações.Paraissoéprecisoadicionarnoarquivospring-context.xmlummapeamentoqueinformaao

SpringMVCqueeledeveignorartodoacessoaconteúdoestático.

<mvc:default-servlet-handler/>

JáconheceoscursosonlineAlura?

11.20 CONFIGURAR O SPRING MVC PARA ACESSAR ARQUIVOSCOMUNS

174 11.20CONFIGURAROSPRINGMVCPARAACESSARARQUIVOSCOMUNS

Page 184: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. Abraoarquivospring-context.xmleacrescente:

<mvc:default-servlet-handler/>

Na pasta WebContent crie uma nova pasta resources, vamos colocar nela tudo relativo a

conteúdoestáticodonossosistema.

1. Vamos adicionar AJAX na nossa aplicação. Para isso, utilizaremos o jQuery que precisamosimportarparanossoprojetoeemnossaspáginas.

Váatéapastadearquivosdocurso,em21/projeto-agenda/;

Copieodiretóriojsecole-odentrodeWebContent/resources no seuprojeto fj21-tarefas;

Casovocêestejaemcasa,façaodownloademhttps://jquery.com/download/

PrecisamosimportarojQueryemnossapáginadelistagem.Paraisso,adicionelogoapósaTag<html>oseguintecódigonoarquivolista.jsp:

<head><scripttype="text/javascript"src="resources/js/jquery.js"></script></head>

Pronto,importamosojQueryparanossaaplicação.

2. Casoatarefanãoestejafinalizada,queremosqueelapossuaumnovolinkquesechamará"Finalizaragora".Aoclicarnele,seráchamadaviaAJAXumaActionquemarcaráatarefacomofinalizada

eadatadehojeserámarcadacomoadatadefinalizaçãodamesma.

Altereacolunaquemostraatarefacomonão finalizadanoarquivolista.jsp.Adicioneumlinkqueaoserclicada,chamaráumafunçãoJavascriptpassandooidda tarefaparafinalizar.

Tambémadicioneumaidparacadaelemento<td>.

Noarquivoprocureoc:ifparatarefasnãofinalizadas,altereoelementotddentroc:if:

<c:iftest="${tarefa.finalizadoeqfalse}"><tdid="tarefa_${tarefa.id}"><ahref="#"onClick="finalizaAgora(${tarefa.id})">Finalizaagora!</a></td></c:if>

Criea funçãoJavascriptfinalizaAgora para chamar a açãoque criaremos a seguir via uma

requisiçãoPOST:

<!--ComeçodapáginacomoimportdoJavascript--><body><scripttype="text/javascript">functionfinalizaAgora(id){

11.21EXERCÍCIOS:AJAX

11.21EXERCÍCIOS:AJAX 175

Page 185: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

$.post("finalizaTarefa",{'id':id},function(){//selecionandooelementohtmlatravésda//IDealterandooHTMLdele$("#tarefa_"+id).html("Finalizado");});}</script>

<ahref="novaTarefa">Criarnovatarefa</a><br/><br/>

<table><!--Restodapáginacomatabela-->

3. Vamos criar o método para finalizar a tarefa. Após o mesmo ser executado, ele não deverá nosredirecionarparalugarnenhum,apenasindicarqueaexecuçãoocorreucomsucesso.

AbraaclasseTarefasControllerAdicioneométodofinalizacomoconteúdo:

@ResponseBody@RequestMapping("finalizaTarefa")publicvoidfinaliza(Longid){JdbcTarefaDaodao=newJdbcTarefaDao();dao.finaliza(id);}

Acesse a listagem http://localhost:8080/fj21-tarefas/listaTarefas e clique no novo link parafinalizartarefa.Atelamudasemprecisarumaatualizaçãointeiradapágina.

4. (Opcional,Avançado)Nomesmoestilodoexercícioanterior,useo jQueryparaacionarométodoremoveTarefaquandoclicadoemumbotãode"excluir".Paraisso,crieumanovacolunanatabela

com um link que o onClick vai chamar o endereço associado a removeTarefa, e via AJAX

devemosremoveralinhadatabela.PraissovocêpodeusarumrecursopoderosodojQueryepedirquesejaescondidaalinhadeondeveiooclique:

$(elementoHtml).closest("tr").hide();

Dessamaneiravocênemprecisariausaridsnastrs.

176 11.21EXERCÍCIOS:AJAX

Page 186: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

AgoraaofinalizarnossatarefaviaAJAXousuáriotemumfeedbacknaalteraçãodoHTMLdeNãoFinalizadoparaFinalizado.Porémtodasastarefasfinalizadaspossuemacolunadedatadefinalizaçãopreenchidas,menosasqueacabamosdefinalizar.

Pararesolveresseproblema,dealgumaformaonossoControllerdeveriapassarumadataparanossojQuery.Mascomo?Umasoluçãopossívelseriaescrevê-ladiretonoresponse.Algoparecidocomisso:

@RequestMapping("finalizaTarefa")publicvoidfinaliza(Longid,HttpServletResponseresponse)throwsIOException{JdbcTarefaDaodao=newJdbcTarefaDao();dao.finaliza(id);DatedataDeFinalizacao=dao.buscaPorId(id).getDataFinalizacao().getTime();Stringdata=newSimpleDateFormat("dd/MM/yyyy").format(dataDeFinalizacao);response.getWriter().write(data);response.setStatus(200);}

ResolvenossoproblemamasaindaassimteríamosqueficartrabalhandodiretoemumcamadamaisbaixaquesãoasclassesdeHTTPServletRequesteHTTPServletResponse.Agoraalémdefinalizar

uma tarefa nossa action tem as responsabilidades de buscar pela data finalizada, formatar a data,escrevernoresponseemudarostatuspara200.Responsabilidadedemais,nãoémesmo?

RetornarumaJSPjánostrazobenefíciodostatus200,necessárioparanossafunçãodecallback

no jQuery. Sabendo disso usaremos uma JSP para renderizar a data formatada.Mas antes é precisopassaressadataanossaJSP,ousimplesmentepassarumaTarefaparaelaedepoisfazercomquea

ActionretorneaStringreferenteaJSP.

@RequestMapping("finalizaTarefa")publicStringfinaliza(Longid,Modelmodel){JdbcTarefaDaodao=newJdbcTarefaDao();dao.finaliza(id);model.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/dataFinalizada";}

AgorasófaltarealmentecriarmosoarquivodataFinalizadanapasta/WEB-INF/views/tarefa

eformataradatausandoatag.

<%@tagliburi="http://java.sun.com/jsp/jstl/fmt"prefix="fmt"%>

<fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/>

Legal, já renderizamos uma data formatada e por consequência o status 200 é enviado para o

jQuery.SóqueatéagoranãofizemosnadacomessadataqueoJSPrenderizou.Paraquesepeguealgoenviado pelo nosso servidor, a função de callback deve receber um parâmetro com esse conteúdo.Vamosexecutarumalertcomestavariável.

<scripttype="text/javascript">

11.22PARASABERMAIS:ALTERANDOVALORDADATACOMAJAX

11.22PARASABERMAIS:ALTERANDOVALORDADATACOMAJAX 177

Page 187: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

functionfinalizaAgora(id){$.post("finalizaTarefa",{'id':id},function(resposta){$("#tarefa_"+id).html("Finalizado");alert(resposta);});}</script>

Aexecuçãodessealertnosmostraadata,faltaapenasinseri-laemlugarapropriado.Vamosusar

amesmaestratégiaqueusamosparamudardeNãoFinalizadoparaFinalizado,atrelandoumidanossa<td>referenteaocampodededata.

<tdid="tarefa_data_${tarefa.id}"><fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/></td>

Fazendoissobastatrocarmosoconteúdodo<td>nafunção.

<scripttype="text/javascript">functionfinalizaAgora(id){$.post("finalizaTarefa",{'id':id},function(resposta){$("#tarefa_"+id).html("Finalizado");$("#tarefa_data_"+id).html(resposta);});}</script>

Onosso desafio foi cumprido de forma elegante,mas ainda assim poderíamosmelhorar o nossocódigo.AfunçãodecallbackdoAJAXtemquemodificardois<td>'se issotornariarepetitivopara

modeloscommaisalteraçõesqueanossaTarefa.Sabendoqueafunçãorecebeapenasumparâmetro

deresposta,teríamosmaisproblemasaoterquepassarmaisdeumparâmetroaela.Comoresolverestaquestão?Umasoluçãoviávelépassaraprópria<tr>, completa, comas alteraçãonecessárias.Para

issoumaalteraçãonaJSPsefaznecessária.

<%@tagliburi="http://java.sun.com/jsp/jstl/fmt"prefix="fmt"%>...<td>${tarefa.id}</td><td>${tarefa.descricao}</td><td>Finalizada</td><td><fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/></td><td><ahref="removeTarefa?id=${tarefa.id}">Remover</a></td><td><ahref="mostraTarefa?id=${tarefa.id}">Alterar</a></td>

UmaalteraçãononomedoarquivodataFinalizada.jspseriamaisdoquerecomendada,jáque

agoranãopossui apenasumadata e sim todas as alteraçõesdeuma<tr>.Vamos renomeá-lopara

finalizada.jsp . Sem esquecer de modificar o retorno da action de tarefa/dataFinalizada para

tarefa/finalizada:

@RequestMapping("finalizaTarefa")publicStringfinaliza(Longid,Modelmodel){...return"tarefa/finalizada";

178 11.22PARASABERMAIS:ALTERANDOVALORDADATACOMAJAX

Page 188: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

Agoraqueretornamosuma<tr>comtodasasalteraçõesvamosmodificarafunçãodecallback,

para que ela apenasmodifique o conteúdo da <tr> correspondente a tarefa finalizada. Para isso é

precisodiferenciarum<tr>dooutro.Vamosutilizaragoraumidnaprópria<tr>eremoveremosos

idsdesnecessáriosdos<td>'s.

<table>...<c:forEachitems="${tarefas}"var="tarefa"><trid="tarefa_${tarefa.id}"><td>${tarefa.id}</td><td>${tarefa.descricao}</td>

<c:iftest="${tarefa.finalizadoeqtrue}"><td>Finalizado</td></c:if>

<c:iftest="${tarefa.finalizadoeqfalse}"><td><ahref="#"onClick="finalizaAgora(${tarefa.id})">Finalizar</a></td></c:if>

<td><fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/></td>

<td><ahref="removeTarefa?id=${tarefa.id}">Remover</a></td><td><ahref="mostraTarefa?id=${tarefa.id}">Alterar</a></td>

</tr>

</c:forEach>....

</table>

Eporúltimo,faltamudarafunçãodecallbackparaqueestamodifiqueoconteúdodo<tr>.

...$.post("finalizaTarefa",{'id':id},function(resposta){$("#tarefa_"+id).html(resposta);});...

Agorasim,temosumcódigosimplesefácildemanter.Tudooqueumbomprogramadorgostariadeencontrar.

11.22PARASABERMAIS:ALTERANDOVALORDADATACOMAJAX 179

Page 189: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

1. Vamos buscar uma tarefa e passá-la para nossa JSP através do Model. Abra oTarefasController.javaemodifiqueaactionquefinalizaumatarefaparaoquesegue:

@RequestMapping("finalizaTarefa")publicStringfinaliza(Longid,Modelmodel){JdbcTarefaDaodao=newJdbcTarefaDao();dao.finaliza(id);model.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/finalizada";}

1. Agorafaltacriarmosoarquivofinalizada.jspdentrododiretório:/WEB-INF/views/tarefa/.

Quedeveráteroseguinteconteúdodarelacionadaatarefafinalizada.

<%@tagliburi="http://java.sun.com/jsp/jstl/fmt"prefix="fmt"%>...<td>${tarefa.id}</td><td>${tarefa.descricao}</td><td>Finalizada</td><td><fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/></td><td><ahref="removeTarefa?id=${tarefa.id}">Remover</a></td><td><ahref="mostraTarefa?id=${tarefa.id}">Alterar</a></td>

1. Porúltimodevemosmodificaroarquivotarefa/lista.jspparaqueele tenhaumidentificador

decadalinha,ouseja,elementodatabela.Demaneiraanálogaaoquefoifeitonoexercícioanteriorvamosconcatenarcomoidda tarefaumvalordetarefa_.Lembre-sede removeros idsdos

outros<td>'sjáqueelesnãoserãonecessáriosepodemestarcomomesmonomedoidentificadorda<tr>.

....<c:forEachitems="${tarefas}"var="tarefa"><trid="tarefa_${tarefa.id}"><td>${tarefa.id}</td><td>${tarefa.descricao}</td>

VocêpodetambémfazerocursodatadessaapostilanaCaelum

11.23EXERCÍCIOSOPCIONAIS:MELHORANDONOSSOAJAX

180 11.23EXERCÍCIOSOPCIONAIS:MELHORANDONOSSOAJAX

Page 190: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<c:iftest="${tarefa.finalizadoeqtrue}"><td>Finalizado</td></c:if>

<c:iftest="${tarefa.finalizadoeqfalse}"><td><ahref="#"onClick="finalizaAgora(${tarefa.id})">Finalizar</a></td></c:if>

<td><fmt:formatDatevalue="${tarefa.dataFinalizacao.time}"pattern="dd/MM/yyyy"/></td>....</tr>.....

1. EagoraparafazerusodoconteúdorenderizadopelaJSP,énecessárioqueafunçãodecallbackdoAJAX receba como parâmetro esse conteúdo. Vamos alterar a função do finalizaAgora no

mesmoarquivolista.jsp,paraoquesegue:

<scripttype="text/javascript">functionfinalizaAgora(id){$.post("finalizaTarefa",{'id':id},function(resposta){$("#tarefa_"+id).html(resposta);});}</script>

1. Reinicieoservidoreverifiquequeagoraaoclicarno linkFinalizar o usuário tema alteração

tantodeNãoFinalizadaparaFinalizadaquandoumamudançanadatadefinalização.

11.23EXERCÍCIOSOPCIONAIS:MELHORANDONOSSOAJAX 181

Page 191: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO12

"Experiênciaéapenasonomequedamosaosnossoserros."--OscarWilde

Nessecapítulo,vocêaprenderá:

Oescopodesessãoecomoelefunciona;Oquesãointerceptadores;Implantarsuaaplicaçãoemqualquercontainer.

Écomumhojeemdiaacessarmosalgumsitequepeçaparafazermosnossologinparapodermosteracesso a funcionalidades da aplicação. Esse processo também é conhecido como autenticação.Mas,comoositesabe,nasrequisiçõesseguintesquefazemos,quemsomosnós?

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

OprotocoloHTTPutilizadoparaoacessoàpáginasélimitadopornãomanterdetalhescomoqueméquementreumaconexãoeoutra.Pararesolverisso,foiinventadoumsistemaparafacilitaravidados

SPRINGMVC:AUTENTICAÇÃOEAUTORIZAÇÃO

12.1AUTENTICANDOUSUÁRIOS:COMOFUNCIONA?

Seuslivrosdetecnologiaparecemdoséculopassado?

12.2COOKIES

182 12SPRINGMVC:AUTENTICAÇÃOEAUTORIZAÇÃO

Page 192: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

programadores.

Umcookieénormalmenteumpardestringsguardadonocliente,assimcomoummapadestrings.Essepardestringspossuidiversaslimitaçõesquevariamdeacordocomoclienteutilizado,oquetornaa técnicadeutilizá-los algodoqualnão sedevaconfiarmuito. Jáqueas informaçõesdocookie sãoarmazenadas no cliente, o mesmo pode alterá-la de alguma maneira... sendo inviável, por exemplo,guardaronomedousuáriologado...

Quando um cookie é salvo no cliente, ele é enviado de volta ao servidor toda vez que o clienteefetuarumanovarequisição.Destaforma,oservidorconsegueidentificaraqueleclientesemprecomosdadosqueocookieenviar.

Umexemplodebomusodecookiesénatarefadelembraronomedeusuárionapróximavezqueelequiserselogar,paraquenãotenhaqueredigitaromesmo.

Cadacookiesóéarmazenadoparaumwebsite.Cadawebsitepossuiseuspróprioscookieseestesnãosãovistosemoutrapágina.

UsarCookies parece facilitarmuito a vida,mas através de um cookie não é possívelmarcar umclientecomumobjeto,somentecomStrings.Imaginegravarosdadosdousuáriologadoatravésde

cookies.Serianecessárioumcookieparacadaatributo:usuario,senha,id,datadeinscrição,

etc.Semcontarafaltadesegurança.

OCookietambémpodeestardesabilitadonocliente,sendoquenãoserápossívellembrarnadaqueousuáriofez...

Umasessãofacilitaavidadetodosporpermitiratrelarobjetosdequalquer tipoaumcliente,nãosendolimitadasomenteàstringseéindependentedecliente.

A abstração daAPI facilita o trabalho do programador pois ele não precisa saber como é que asessãofoiimplementadanoservletcontainer,elesimplesmentesabequeafuncionalidadeexisteeestáláparaouso.Seoscookiesestiveremdesabilitados,asessãonãofuncionaráedevemosrecorrerparaumatécnica(trabalhosa)chamadaurl-rewriting.

A sessão nadamais é que um tempo que o usuário permanece ativo no sistema. A cada páginavisitada, o tempo de sessão é zerado. Quando o tempo ultrapassa um limite demarcado no arquivoweb.xml,oclienteperdesuasessão.

Paraconfigurar3minutoscomoopadrãode tempoparaousuárioperderasessãobasta incluiro

12.3SESSÃO

12.4CONFIGURANDOOTEMPOLIMITE

12.3SESSÃO 183

Page 193: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

seguintecódigonoarquivoweb.xml:

<session-config><session-timeout>3</session-timeout></session-config>

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Podemoscriarumaaçãoquefaráo logindaaplicação.Casoousuário informadona telade loginexista,guardaremosomesmonasessãoeentraremosnosistema,ecasonãoexistavamosvoltarparaapáginadelogin.

OSpringMVCnospossibilitareceberasessãoemqualquermétodo,sóéprecisocolocaroobjetoHttpSessioncomoparâmetro.Porexemplo:

@ControllerpublicclassLoginController{

publicStringefetuaLogin(HttpSessionsession){//....}}

AsessãoéparecidacomumobjetodotipoMap<String,Object>,podemosguardarnelaqualquer

objeto que quisermos dando-lhes uma chave que é umaString. Portanto, para logarmos o usuário naaplicação poderíamos criar uma ação que recebe os dados do formulário de login e a sessãoHTTP,guardandoousuáriologadodentrodamesma:

@RequestMapping("efetuaLogin")publicStringefetuaLogin(Usuariousuario,HttpSessionsession){if(newJdbcUsuarioDao().existeUsuario(usuario)){session.setAttribute("usuarioLogado",usuario);return"menu";}else{//....}}

Agoraéamelhorhoradeaprenderalgonovo

12.5REGISTRANDOOUSUÁRIOLOGADONASESSÃO

184 12.5REGISTRANDOOUSUÁRIOLOGADONASESSÃO

Page 194: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. Vamos criar o formulário de Login, uma ação para chamar este formulário e uma outra querealmenteautenticaousuário.

Crie a página formulario-login.jsp dentro de WebContent/WEB-INF/views com o

conteúdo:

<html><body><h2>PáginadeLogindasTarefas</h2><formaction="efetuaLogin"method="post">Login:<inputtype="text"name="login"/><br/>Senha:<inputtype="password"name="senha"/><br/><inputtype="submit"value="Entrarnastarefas"/></form></body></html>

Crie uma nova classe chamada LoginController no pacote

br.com.caelum.tarefas.controller . Crie um método para exibir o formulario-

login.jsp:

@ControllerpublicclassLoginController{

@RequestMapping("loginForm")publicStringloginForm(){return"formulario-login";}}

Namesma classe LoginController coloque o método que verifica o existência do usuario.

AcrescenteométodoefetuaLogin:

@RequestMapping("efetuaLogin")publicStringefetuaLogin(Usuariousuario,HttpSessionsession){if(newJdbcUsuarioDao().existeUsuario(usuario)){session.setAttribute("usuarioLogado",usuario);return"menu";}return"redirect:loginForm";}

Apósousuáriose logar,eleseráredirecionadoparaumapáginaqueconterá linksparaasoutraspáginasdosistemaeumamensagemdeboasvindas.

Crieapáginamenu.jspemWebContent/WEB-INF/viewscomocódigo:

<html><body><h2>PáginainicialdaListadeTarefas</h2><p>Bemvindo,${usuarioLogado.login}</p><ahref="listaTarefas">Cliqueaqui</a>paraacessaralistadetarefas

12.6EXERCÍCIO:FAZENDOOLOGINNAAPLICAÇÃO

12.6EXERCÍCIO:FAZENDOOLOGINNAAPLICAÇÃO 185

Page 195: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

</body></html>

Acesseapáginadeloginemhttp://localhost:8080/fj21-tarefas/loginFormeseloguenaaplicação.

Verifiqueobancodedadosparaterumloginesenhaválidos.Paraisso,noterminalfaça:

mysql-urootusefj21;select*fromusuarios;

Sehouversenhanobanco,troqueoprimeirocomandopormysql-uroot-p,usandoasenha

corretaprobanco.Seatabelanãoexistir,vocêpodecriá-laexecutandoocomando:

createtableusuarios(loginVARCHAR(255),senhaVARCHAR(255));

(Dica: o códigopara criar essa tabela pode ser encontradono arquivocriacao-tabela.sql na

pasta21/projeto-tarefas/mysql)

Casonãoexistausuárioscadastrados,cadastrealgumutilizandoomesmoterminalabertoantesdaseguintemaneira:

insertintousuarios(login,senha)values('seu_usuario','sua_senha');

Nãopodemospermitirquenenhumusuárioacesseastarefassemqueeleestejalogadonaaplicação,pois essa não é uma informação pública. Precisamos portanto garantir que antes de executarmosqualqueraçãoousuárioestejaautenticado,ouseja,armazenadonasessão.

UtilizandooSpringMVC,podemosutilizaro conceitodos Interceptadores, que funcionamcomoFiltrosqueaprendemosanteriormente,mascomalgumasfuncionalidadesamaisqueestãorelacionadasaoframework.

Para criarmos um Interceptador basta criarmos uma classe que implemente a interface org.springframework.web.servlet.HandlerInterceptor . Ao implementar essa interface,

precisamosimplementar3métodos:preHandle,postHandleeafterCompletion.

OsmétodospreHandleepostHandleserãoexecutadosantesedepois,respectivamente,daação.

EnquantoométodoafterCompletionéchamadonofinaldarequisição,ousejaapósterrenderizadoo

JSP.

Paranossaaplicaçãoqueremosverificaroacessoantesdeexecutarumaação,porissovamosusarapenas o método preHandle da interface HandlerInterceptor . Porém, usando a interface

12.7 BLOQUEANDO ACESSOS DE USUÁRIOS NÃO LOGADOS COMINTERCEPTADORES

186 12.7BLOQUEANDOACESSOSDEUSUÁRIOSNÃOLOGADOSCOMINTERCEPTADORES

Page 196: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

HandlerInterceptor somos obrigados implementar todos os métodos definidos na interface.

Queremos usar apenas o preHandle . Por isso o Spring MVC oferece uma classe auxiliar

(HandlerInterceptorAdapter) que já vem com uma implementação padrão para cadamétodo da

interface.Entãoparafacilitarotrabalhovamosestenderessaclasseesobrescreverapenasométodoqueédonossointeresse:

publicclassAutorizadorInterceptorextendsHandlerInterceptorAdapter{

@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objectcontroller)throwsException{//....response.sendRedirect("loginForm");returnfalse;}}

O método preHandle recebe a requisição e a resposta, além do controlador que está sendo

interceptado. O retorno é um booleano que indica se queremos continuar com a requisição ou não.Portanto,aclasseAutorizadorInterceptorsódevedevolvertrueseousuárioestálogado.Casoo

usuárionãoestejaautorizadovamosredirecionarparaoformuláriodelogin.

ParapegarousuáriologadoéprecisoacessarasessãoHTTP.Oobjetorequestpossuiummétodo

quedevolveasessãodousuárioatual:

HttpSessionsession=request.getSession();

DessamaneirapodemosverificarnoInterceptadoraexistênciadoatributousuarioLogado:

publicclassAutorizadorInterceptorextendsHandlerInterceptorAdapter{

@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objectcontroller)throwsException{

if(request.getSession().getAttribute("usuarioLogado")!=null){returntrue;}

response.sendRedirect("loginForm");returnfalse;}}

Falta só mais uma verificação. Existem duas ações na nossa aplicação que não necessitam deautorização.SãoasaçõesdoLoginController,necessáriasparapermitiraautenticaçãodousuário.

Alémdisso,vamosgarantirtambémqueapastaderesourcespodeseracessadamesmosemlogin.

Essa pasta possui as imagens, css e arquivos JavaScript. No entanto a classeAutorizadorInterceptorfica:

12.7BLOQUEANDOACESSOSDEUSUÁRIOSNÃOLOGADOSCOMINTERCEPTADORES 187

Page 197: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicclassAutorizadorInterceptorextendsHandlerInterceptorAdapter{

@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objectcontroller)throwsException{

Stringuri=request.getRequestURI();if(uri.endsWith("loginForm")||uri.endsWith("efetuaLogin")||uri.contains("resources")){returntrue;}

if(request.getSession().getAttribute("usuarioLogado")!=null){returntrue;}

response.sendRedirect("loginForm");returnfalse;}}

Ainda precisamos registrar o nosso novo interceptador. Mas o Spring MVC não permite quefaçamos issovia anotações, entãousaremos a configuraçãoviaXMLnesse caso. Jávimoso arquivo spring-context.xml , nele vamos usar o tag mvc:interceptors para cadastrar a classe

AutorizadorInterceptor:

<mvc:interceptors><beanclass="br.com.caelum.tarefas.interceptor.AutorizadorInterceptor"/></mvc:interceptors>

Caso seja necessário alguma ordem na execução de diversos interceptors, basta registrá-los nasequênciadesejadadentrodatagmvc:interceptors.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

EditoraCasadoCódigocomlivrosdeumaformadiferente

12.8EXERCÍCIOS:INTERCEPTANDOASREQUISIÇÕES

188 12.8EXERCÍCIOS:INTERCEPTANDOASREQUISIÇÕES

Page 198: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. VamoscriarumInterceptorquenãopermitiráqueousuárioacesseasaçõessemantesterlogado

naaplicação.

CrieaclasseAutorizadorInterceptornopacotebr.com.caelum.tarefas.interceptor

Estenda a classe HandlerInterceptorAdapter do package

org.springframework.web.servlet.handler

SobrescreveométodopreHandle.OusuáriosópodeacessarosmétodosdoLoginController

SEMterfeitoo login.Casooutra lógicasejachamadaéprecisoverificarseousuárioexistenasessão.Existindonasessão,seguiremosofluxonormalmente,casocontrário indicaremosqueousuário não está logado e que deverá ser redirecionado para o formulário de login. O códigocompletodointerceptadorfica:

publicclassAutorizadorInterceptorextendsHandlerInterceptorAdapter{

@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objectcontroller)throwsException{

Stringuri=request.getRequestURI();if(uri.endsWith("loginForm")||uri.endsWith("efetuaLogin")||uri.contains("resources")){returntrue;}

if(request.getSession().getAttribute("usuarioLogado")!=null){returntrue;}

response.sendRedirect("loginForm");returnfalse;}}

Temos que registrar o nosso novo interceptador noXML do spring.Abra o arquivo spring-

context.xml.Dentrodatag<beans>adicione:

<mvc:interceptors><beanclass="br.com.caelum.tarefas.interceptor.AutorizadorInterceptor"/></mvc:interceptors>

2. Reinicieoservidoretenteacessaralistadetarefasemhttp://localhost:8080/fj21-tarefas/listaTarefas.Vocêdeveráserredirecionadoparaoformuláriodelogin.

1. Façaologoutdaaplicação.Crieumlinknomenu.jspqueinvocaráummétodoqueremoveráo

12.9EXERCÍCIOSOPCIONAIS:LOGOUT

12.9EXERCÍCIOSOPCIONAIS:LOGOUT 189

Page 199: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

usuáriodasessãoeredirecioneanavegaçãoparaaactiondoformuláriodelogin(loginForm).

Nomenu.jspacrescente:

<ahref="logout">Sairdosistema</a>

NaclasseLoginControlleradicioneométodoparaologouteinvalideasessãodousuário:

@RequestMapping("logout")publicStringlogout(HttpSessionsession){session.invalidate();return"redirect:loginForm";}

190 12.9EXERCÍCIOSOPCIONAIS:LOGOUT

Page 200: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO13

"Fazertroçadafilosofiaé,naverdade,filosofar"--BlaisePascal

Nessecapítulo,vocêaprenderá:

OqueéumcontainerdeinversãodecontrollerComogerenciarqualquerobjetoeinjetardependênciascomoSpringImplantarsuaaplicaçãoemqualquercontainer.

NanossaclasseTarefasControllerusamosoJdbcTarefaDaoparaexecutarosmétodosmais

comunsnobancodedados relacionado comaTarefa. Em cadamétodo do controller criamos um

JdbcTarefaDaoparaacessarobanco.ReparenocódigoabaixoquantasvezesinstanciamosoDAOna

mesmaclasse:

@ControllerpublicclassTarefasController{

@RequestMapping("mostraTarefa")publicStringmostra(Longid,Modelmodel){JdbcTarefaDaodao=newJdbcTarefaDao();model.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/mostra";}

@RequestMapping("listaTarefas")publicStringlista(Modelmodel){JdbcTarefaDaodao=newJdbcTarefaDao();model.addAttribute("tarefas",dao.lista());return"tarefa/lista";}

@RequestMapping("adicionaTarefa")publicStringadiciona(@ValidTarefatarefa,BindingResultresult){

if(result.hasFieldErrors("descricao")){return"tarefa/formulario";}

JdbcTarefaDaodao=newJdbcTarefaDao();dao.adiciona(tarefa);return"tarefa/adicionada";

SPRINGIOCEDEPLOYDAAPLICAÇÃO

13.1 MENOS ACOPLAMENTO COM INVERSÃO DE CONTROLE EINJEÇÃODEDEPENDÊNCIAS

13SPRINGIOCEDEPLOYDAAPLICAÇÃO 191

Page 201: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

//outrosmétodosremove,alteraefinalizatambémcriamaJdbcTarefaDao}

AclasseTarefasControllerinstanciaumobjetodotipoJdbcTarefaDaomanualmente.Estamos

repetindoacriaçãodoDAOemcadamétodo.Podemosmelhorarocódigo,criaroJdbcTarefaDaono

construtordaclasseTarefasControllereusarumatributo.Assimpodemosapagartodasaslinhasde

criaçãodoDAO:

@ControllerpublicclassTarefasController{

privateJdbcTarefaDaodao;

publicTarefasController(){this.dao=newJdbcTarefaDao();}

@RequestMapping("mostraTarefa")publicStringmostra(Longid,Modelmodel){//daojáfoicriadomodel.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/mostra";}

@RequestMapping("listaTarefas")publicStringlista(Modelmodel){//daojáfoicriadomodel.addAttribute("tarefas",dao.lista());return"tarefa/lista";}

//outrosmétodostambémaproveitamoatributodao

}

Onossocódigomelhorou,poistemosmenoscódigoparamanter,mashámaisumproblema.ReparequecontinuamosresponsáveispelacriaçãodoDAO.AclassequefazusodesteDAOestáintimamenteligada com a maneira de instanciação do mesmo, fazendo com que ela mantenha um alto grau deacoplamento.

DizemosqueaclasseTarefasControllertemumadependênciacomoJdbcTarefaDao.VáriosmétodosdeladependemdoJdbcTarefaDao.Nocódigoacimacontinuamosadarnewdiretamentena

implementação JdbcTarefaDao para usá-la. Nossa aplicação cria a dependência, chamandodiretamenteaclasseespecífica.

O problema em gerenciar a dependência diretamente na aplicação fica evidente se analisamos aclasse JdbcTarefaDao . Se a classe precisar de um processo de construção mais complicado,

precisaremosnospreocuparcomissoemtodososlugaresondecriamosoJdbcTarefaDao.

ParaentenderissovamosverificaroconstrutordoDAO:

192 13.1MENOSACOPLAMENTOCOMINVERSÃODECONTROLEEINJEÇÃODEDEPENDÊNCIAS

Page 202: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicclassJdbcTarefaDao{

privatefinalConnectionconnection;

publicJdbcTarefaDao(){try{this.connection=newConnectionFactory().getConnection();}catch(SQLExceptione){thrownewRuntimeException(e);}}//métodosomitidos}

Reparequeaquiexisteomesmoproblema.ODAOtambémresolveasuadependênciaecriaatravésda ConnectionFactory, a conexão. Estamos acoplados à classe ConnectionFactory enquanto

apenasqueremosumaconexão.Aclasseestácomaresponsabilidadedeprocuraradependência.Essaresponsabilidadedeveestaremoutrolugar.Paramelhorar,vamosentãodeclararadependênciaemumlugar natural que é o construtor. O código fica muito mais simples e não precisa mais daConnectionFactory:

publicclassJdbcTarefaDao{

privatefinalConnectionconnection;

publicJdbcTarefaDao(Connectionconnection){this.connection=connection;}

//métodosomitidos}

Jácomessapequenamudança,nãopodemoscriaroJdbcTarefaDaosemnospreocuparmoscoma

conexãoantes.VejacomoficariaocódigodaclasseTarefasController:

@ControllerpublicclassTarefasController{

privateJdbcTarefaDaodao;

publicTarefasController(){try{Connectionconnection=newConnectionFactory().getConnection();this.dao=newJdbcTarefaDao(connection);}catch(SQLExceptione){thrownewRuntimeException(e);}}//métodosomitidos}

AclasseTarefasControllernãosócriaráoDAO,comotambémaconexão.Jádiscutimosque

nãoqueremosserresponsáveis,entãovamosagirigualaoJdbcTarefaDaoedeclararadependênciano

construtor.Novamentevaisimplificardemaisonossocódigo:

@Controller

13.1MENOSACOPLAMENTOCOMINVERSÃODECONTROLEEINJEÇÃODEDEPENDÊNCIAS 193

Page 203: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

publicclassTarefasController{

privateJdbcTarefaDaodao;

publicTarefasController(JdbcTarefaDaodao){this.dao=dao;}

//métodosomitidos}

Assimcadaclassedelegaadependênciaparacimaenãoseresponsabilizapelacriação.Quemforusar essa classeTarefasController, agora, vai precisar satisfazer as dependências.Mas quem no

finalsepreocupacomacriaçãodoDAOecomaconexão?

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

OpadrãodeprojetosDependencyInjection(DI)(Injeçãodedependências),procuraresolveressesproblemas.Aideiaéqueaclassenãomaisresolvaassuasdependênciasporcontaprópriamasapenasdeclaraquedependedealgumaoutraclasse.Edealgumaoutraformaquenãosabemosainda,alguémresolverá essa dependência para nós. Alguém pega o controle dos objetos que liga (ou amarra) asdependências.Nãoestamosmaisnocontrole,háalgumcontainerquegerenciaasdependênciaseamarratudo.Essecontainerjáexistiaejáusamoselesemsaber.

Reparequecom@Controller jádefinimosqueanossaclasse fazpartedoSpringMVC,masa

anotaçãovaialémdisso.TambémdefinimosquequeremosqueoSpringcontroleoobjeto.Springénofundoumcontainerquedánewparanóse tambémsabe resolvere ligarasdependências.Por isso,oSpringtambéméchamadoContainerIoC(InversionofControl)ouContainerDI.

Essas são as principais funcionalidades de qualquer container de inversão de controle/injeção dedependência. O Spring é um dos vários outros containers disponíveis no mundo Java. Segue uma

JáconheceoscursosonlineAlura?

13.2CONTAINERDEINJEÇÃODEDEPENDÊNCIAS

194 13.2CONTAINERDEINJEÇÃODEDEPENDÊNCIAS

Page 204: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

pequenalistacomoscontainersmaisfamosos:

SpringIoCousóSpring basedequalquerprojetoSpring,popularizouDI eodesenvolvimentocomPOJOsJBossSeam2ContainerDIqueseintegramuitobemcomJSF,principalmentenaversão1.2doJSFGuiceContainerDIcriadopeloGooglequefavoreceuconfiguraçõesprogramáticassemXMLCDIEspecificaçãoqueentroucomoJavaEE6,fortementeinfluenciadopeloJBossSeameGuicePicoContainermuitoleveeflexível,foipioneironessaáreaEJB3ContainerJavaEEcomumsuportelimitadoaoDI

OSpringContainersabecriaroobjeto,mastambémligaasdependênciasdele.ComooSpringestánocontrole,eleadministratodoociclodavida.Paraissoacontecerseráprecisodefinirpelomenosduasconfigurações:

declararoobjetocomocomponenteligaradependência

ParareceberoDAOemnossocontrolador,usaremosaanotação@Autowiredacimadoconstrutor

(wire-amarrar).IssoindicaaoSpringqueeleprecisaresolvereinjetaradependência:

@ControllerpublicclassTarefasController{

privateJdbcTarefaDaodao;

@AutowiredpublicTarefasController(JdbcTarefaDaodao){this.dao=dao;}

//métodosomitidos}

ParaoSpringconseguircriaroJdbcTarefaDaovamosdeclararaclassecomocomponente.Aquio

Springpossuiaanotaçã[email protected]émdisso,

vamos também amarrar a conexão com @Autowired . Veja o código similar a classe

TarefasController:

@RepositorypublicclassJdbcTarefaDao{

privatefinalConnectionconnection;

@AutowiredpublicJdbcTarefaDao(Connectionconnection){this.connection=connection;

13.3CONTAINERSPRINGIOC

13.3CONTAINERSPRINGIOC 195

Page 205: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

//métodosomitidos}

Aousar@Autowirednoconstrutor,oSpringtentadescobrircomoabrirumaconexão,masclaro

que oContainer não faz ideia comqual bancoqueremosnos conectar. Para solucionar isso oSpringoferece uma configuração de XML que define um provedor de conexões. No mundo JavaEE, esteprovedoréchamadoDataSourceeabstraiasconfiguraçõesdeDriver,URL,etcdaaplicação.

Sabendo disso, devemos declarar um DataSource no XML do Spring, dentro do spring-

context.xml:

<beanid="mysqlDataSource"class="org.apache.commons.dbcp2.BasicDataSource"><propertyname="driverClassName"value="com.mysql.jdbc.Driver"/><propertyname="url"value="jdbc:mysql://localhost/fj21"/><propertyname="username"value="root"/><propertyname="password"value="<SENHADOBANCOAQUI>"/></bean>

Definimosumbean noXML.Umbean é apenas um sinônimo para componente.Ao final, cadabean se tornaumobjetoadministradopeloSpring.ParaoSpringContainer,amysqlDataSource, o

JdbcTarefaDao e TarefasController são todos componentes(ou beans) que foram

ligados/amarrados.Ouseja,umdependeaooutro.OSpringvaicriartodoseadministrarociclodavidadeles.

Com a mysqlDataSource definida, podemos injetar ela na JdbcTarefaDao para recuperar a

conexãoJDBC:

@RepositorypublicclassJdbcTarefaDao{

privatefinalConnectionconnection;

@AutowiredpublicJdbcTarefaDao(DataSourcedataSource){try{this.connection=dataSource.getConnection();}catch(SQLExceptione){thrownewRuntimeException(e);}}

//métodosomitidos}

Pronto!Reparequenonossoprojetoocontrolador -- dependedo -->daoque --dependedo -->datasource.OSpringvaiprimeirocriaramysqlDataSource,depoisoDAOenofinalocontrolador.

Eleéoresponsávelpelacriaçãodetodaacadeiadedependências.

196 13.3CONTAINERSPRINGIOC

Page 206: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

SPRINGIOC

Vimos apenas uma parte do poderoso framework Spring. A inversão de controle não só selimitaainjeçãodedependências,oSpringtambémsabeassumiroutraspreocupaçõescomunsentreaplicaçõesdenegócios,comoporexemplo,tratamentodetransaçãoousegurança.

Além disso, é comum integrar outros frameworks e bibliotecas com Spring. Não é raroencontrarprojetosqueusamcontroladoresMVCcomoStrutsouJSFcomSpring.OSpringémuitoflexívelesabegerenciarqualquercomponente,sejaelesimples,comoumaclassedonossoprojeto,ouumframeworksofisticadocomooHibernate.OtreinamentoFJ-27mostracomoaproveitaromelhordoSpring.

Vimos como injetar uma dependência com Spring usando o construtor da classe junto com aanotaçã[email protected]éumpontodeinjeção quedeixaclaroqueessadependência éobrigatóriajáquenãohácomoinstanciaroobjetosempassarpeloseuconstrutor.

Háoutrospontosdeinjeçãocomo,porexemplo,oatributo.Podemosusaraanotação@Autowired

diretamente no atributo. Assim o construtor não é mais necessário, por exemplo podemos injetar oJdbcTarefaDaonaclasseTarefasController:

@ControllerpublicclassTarefasController{

@AutowiredprivateJdbcTarefaDaodao;

//semconstrutor}

Outra forma é criar um método dedicado para dependência, normalmente é usado um setteraplicandoaanotaçãoemcimadométodo:

@ControllerpublicclassTarefasController{

privateJdbcTarefaDaodao;

//semconstrutor

@AutowiredpublicvoidsetTarefaDao(JdbcTarefaDaodao){this.dao=dao;}}

13.4OUTRASFORMASDEINJEÇÃO

13.4OUTRASFORMASDEINJEÇÃO 197

Page 207: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Hávantagensedesvantagensdecadaforma,masemgeraldevemosfavoreceroconstrutor jáqueissoéolugarnaturalparaadependência.Noentantoéimportanteconhecerosoutrospontosdeinjeçãopoisalgunsframeworks/bibliotecasexigemoconstrutorsemparâmetro,obrigandoodesenvolvedorusaro atributo ou método. Como veremos no apêndice até mesmo o Spring precisa em alguns casos oconstrutorsemargumentos.

PARASABERMAIS:@INJECT

AinjeçãodedependênciaéumtópicobastantedifundidonaplataformaJava.Existemvárioscontainercomessepoder,tantoqueissoéopadrãoparaamaioriadosprojetosJavahojeemdia.

CDI(ContexteDependencyInjection,JSR-299)éaespecificaçãoqueestásepopularizando.OSpringsódásuportelimitadoaoCDImasaproveitaasanotaçõespadronizadaspelaespecificaçãoJSR-330.DessamaneirabastaadicionaroJARdaespecificação(java.inject) no classpath e

assimpodemossubstituiraanotação@Autowiredcom@Inject:

@ControllerpublicclassTarefasController{

privateJdbcTarefaDaodao;

@InjectpublicTarefasController(JdbcTarefaDaodao){this.dao=dao;}

//métodosomitidos}

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

VocêpodetambémfazerocursodatadessaapostilanaCaelum

13.5 EXERCÍCIOS: INVERSÃO DE CONTROLE COM O SPRING

198 13.5EXERCÍCIOS:INVERSÃODECONTROLECOMOSPRINGCONTAINER

Page 208: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. ParaconfiguraraDatasourceéprecisocopiardoisJARs.

Primeiro,váaoDesktop,eentrenodiretório21/datasource.

HaverádoisJARs:

commons-dbcp2-2.7.x.jar

commons-pool2-2.8.x.jar.

Copie-os (CTRL+C) e cole-os (CTRL+V) dentro de workspace/fj21-

tarefas/WebContent/WEB-INF/lib

2. Noarquivospring-context.xmladicioneaconfiguraçãodaDatasource:

(Dica: um exemplo dessa configuração encontra-se em 21/datasource/spring-context-

confs.xml)

<beanid="mysqlDataSource"class="org.apache.commons.dbcp2.BasicDataSource"><propertyname="driverClassName"value="com.mysql.jdbc.Driver"/><propertyname="url"value="jdbc:mysql://localhost/fj21"/><propertyname="username"value="root"/><propertyname="password"value=""/></bean>

Repare que definimos as propriedades da conexão, igual a antiga classeConnectionFactory e

lembre-sequeousuáriorootestáconfiguradocomasenha""(aspasvazias).

3. VamosconfiguraraclasseJdbcTarefaDaocomocomponente(Bean)doSpring.Paraisso,adicione

aanotação@Repositoryemcimadaclasse:

@RepositorypublicclassJdbcTarefaDao{...}

UseCtrl+Shift+Oparaimportaraanotação.

1. Alémdisso,altereoconstrutordaclasseJdbcTarefaDao.Useaanotação@Autowiredemcima

doconstrutorecoloqueaDataSourcenoconstrutor.Atravésdelaobteremosumanovaconexão.A

classeDataSourcevemdopackagejavax.sql.

AltereoconstrutordaclasseJdbcTarefaDao:

@AutowiredpublicJdbcTarefaDao(DataSourcedataSource){try{this.connection=dataSource.getConnection();}catch(SQLExceptione){

CONTAINER

13.5EXERCÍCIOS:INVERSÃODECONTROLECOMOSPRINGCONTAINER 199

Page 209: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

thrownewRuntimeException(e);}}

AoalteraroconstrutorvãoaparecererrosdecompilaçãonaclasseTarefasController.

2. AbraaclasseTarefaController.NelavamoscriarumatributoparaaJdbcTarefaDaoegeraro

construtorquerecebeoDAO,novamenteusandoaanotação@Autowired:

@ControllerpublicclassTarefasController{

privatefinalJdbcTarefaDaodao;

@AutowiredpublicTarefasController(JdbcTarefaDaodao){this.dao=dao;}}

3. AlteretodososmétodosquecriamumainstânciadaclasseJdbcTarefaDao.São justamenteesse

métodosquepossuemerrosdecompilação.

Removatodasaslinhascomo:

JdbcTarefaDaodao=newJdbcTarefaDao();

Porexemplo,ométodoparalistarastarefasficacomo:

@RequestMapping("listaTarefas")publicStringlista(Modelmodel){model.addAttribute("tarefas",dao.lista());return"tarefa/lista";}

Arrume os outros erros de compilação, apague todas as linhas que instanciam a classeJdbcTarefaDao.

1. ReinicieoTomcateacesseaaplicação.Tudodevecontinuarfuncionando.2. (opcional)AclasseConnectionFactoryaindaénecessária?

Melhoramosgradativamente anossa aplicaçãomodificandoclasses eutilizando frameworks, tudono lado do servidor, mas o que o usuário final enxerga é o HTML gerado que é exibido em seunavegador.Utilizamosalgumastagsparaestruturarasinformações,masnossaapresentaçãoaindadeixaadesejar.Nãoháatrativoestético.

Paraaprimorarovisual,vamosaplicarCSSnasnossaspáginas.CSSéumacrônimoparaCascadingStyleSheets,quepodemostraduzirparaFolhasdeEstiloemCascata.Osestilosdefinemolayout,porexemplo,acor,otamanho,oposicionamentoesãodeclaradosparaumdeterminadoelementoHTML.O

13.6APRIMORANDOOVISUALATRAVÉSDECSS

200 13.6APRIMORANDOOVISUALATRAVÉSDECSS

Page 210: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CSSalteraaspropriedadesvisuaisdaqueleelementoe,porcascata,todososseuselementosfilhos.Emgeral, o HTML é usado para estruturar conteúdos da página (tabelas, parágrafos, div etc) e o CSSformataedefineaaparência.

AsintaxedoCSStemumaestruturasimples:éumadeclaraçãodepropriedadesevaloresseparadospor um sinal de dois pontos(:), e cada propriedade é separada por um sinal de ponto e vírgula(;), daseguintemaneira:

background-color:yellow;color:blue;

Como estamos declarando as propriedades visuais de um elemento em outro lugar do nossodocumento, precisamos indicar de alguma maneira a qual elemento nos referimos. Fazemos issoutilizandoumseletorCSS.

Noexemploaseguir,usaremososeletorp,quealterarátodososparágrafosdodocumento:

p{color:blue;background-color:yellow;}

Existem várias lugares que podemos declarar os estilos, mas o mais comum é usar um arquivoexterno, com a extensão.css. Para que seja possível declarar nossoCSS em um arquivo à parte,

precisamosindicaremnossodocumentoHTMLumaligaçãoentreeleeafolhadeestilo.

Aindicaçãodeusodeumafolhadeestilosexternadeveserfeitadentrodatag<head>donosso

documentoHTML:

<!DOCTYPEhtml><html><head><linktype="text/css"rel="stylesheet"href="tarefas.css"></head><body><p>Oconteúdodestatagseráexibidoemazulcomfundoamarelo!</p>

</body></html>

Edentrodoarquivotarefas.css:

p{color:blue;background-color:yellow;}

SintaxeeinclusãodeCSS

Declaraçãonoarquivoexterno

13.6APRIMORANDOOVISUALATRAVÉSDECSS 201

Page 211: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

PROGRAMAÇÃOFRONT-END

Apreocupaçãocomaorganizaçãodocódigonãoéexclusivadoprogramadorback-end,istoé,aquelequeprocessaseucódigonoservidor.

Hátambémoprogramadorfront-end,aqueleresponsávelpelocódigoquerodanonavegadordocliente, que também deve se preocupar com a organização de seu código, inclusive com aapresentaçãoatravésdeCSSedeumHTMLbemestruturado.

A Caelum oferece os treinamentosWD-43 eWD-47 para quem quer dominar as melhorestécnicas de desenvolvimentoWeb com semântica perfeita, estilos CSS poderosos e JavaScriptscorretosefuncionais.

1. Noseuprojeto,crieumanovapastacssdentrodapastaWebContent/resources.

2. VáaoDesktopeentrenodiretório21/projeto-tarefas/css.Copieoarquivotarefas.css(CTRL+C)paraapastaWebContent/resources/css(CTRL+V).

3. Abraapáginaformulario-login.jspqueestádentrodapastaWebContent/WEB-INF/views.

4. NapáginaJSP,adicioneumcabeçalho(<head></head>)comolinkparaoarquivoCSS.Adicione

ocabeçalhoentredatag<html>e<body>:

<head><linktype="text/css"href="resources/css/tarefas.css"rel="stylesheet"/></head>

AtravésdolinkdefinimosocaminhoparaoarquivoCSS.

Cuidado:Napáginadeveexistirapenasumcabeçalho(<head></head>).

1. ReinicieoTomcatechamaapáginadelogin:

http://localhost:8080/fj21-tarefas/loginForm

Apáginajádeveaparecercomumvisualnovo.

2. Aplique o mesmo arquivo CSS em todas as outras páginas. Tenha cuidado para não repetir ocabeçalho,algumaspáginasjápossuematag<head>,outrasnão.

Verifiqueoresultadonaaplicação.

13.7EXERCÍCIOSOPCIONAIS:APLICANDOCSSNASPÁGINAS

202 13.7EXERCÍCIOSOPCIONAIS:APLICANDOCSSNASPÁGINAS

Page 212: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Geralmente,aodesenvolvermosumaaplicaçãoWeb,possuímosumambientededesenvolvimentocomumservidorqueestáemnossasmáquinaslocais.Depoisqueodesenvolvimentoestáfinalizadoenossaaplicaçãoestáprontaparairaoar,precisamosenviá-laparaumambientequecostumamoschamarde ambiente de produção. Esse processo de disponibilizarmos nosso projeto em um determinadoambienteéoquechamamosdedeploy(implantação).

Oservidordeproduçãoéolocalnoqualoprojetoestaráhospedadoesetornaráacessívelparaosusuáriosfinais.

Mascomofazemosparaenviarnossoprojetoqueestáemnossasmáquinaslocaisparaumservidorexterno?

OprocessopadrãodedeploydeumaaplicaçãowebemJavaéodecriarumarquivocomextensão.war,quenadamaiséqueumarquivozipcomodiretóriobasedaaplicaçãosendoaraizdozip.

No nosso exemplo, todo o conteúdo do diretórioWebContent pode ser incluído em um arquivotarefas.war.Apóscompactarodiretório,efetuaremosodeploy.

Seuslivrosdetecnologiaparecemdoséculopassado?

13.8DEPLOYDOPROJETOEMOUTROSAMBIENTES

13.8DEPLOYDOPROJETOEMOUTROSAMBIENTES 203

Page 213: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

NoTomcat,bastacopiaroarquivo.warnodiretórioTOMCAT/webapps/.Eleserádescompactadopelo container e um novo contexto chamado tarefas estará disponível. Repare que o novo contextogeradopeloTomcatadotaomesmonomequeoseuarquivo.war,ouseja,nossoarquivochamava-se

tarefas.wareocontextosechamatarefas.

Ao colocarmos o war no Tomcat, podemos acessar nossa aplicação pelo navegador através do

endereço:http://localhost:8080/tarefas/loginForm

1. Vamospraticarcriandoumwareutilizando-o,mas,antesdecomeçarmos,certifique-sedequeo

Tomcatestejanoar.

CliquecomobotãodireitonoprojetoeváemExport

Digitenabuscawarfile

CliquenobotãoBrowseeescolhaapastadoseuusuárioeonometarefas.war.

13.9EXERCÍCIOS:DEPLOYCOMWAR

204 13.9EXERCÍCIOS:DEPLOYCOMWAR

Page 214: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CliqueemFinish

Pronto,nossowarestácriado!

2. Vamosinstalarnossowar!

AbraoFileBrowser

Cliquedadireitanoarquivotarefas.wareescolhaCut(Recortar).

Vá para o diretórioapache-tomcat, Certifique-se de que seuTomcat esteja rodando, para issoacesseodiretóriobin/dotomcatviaterminaleexecuteoscriptstartup.sh.

Acesseodiretóriowebapps.

Coleoseuarquivoaqui:(Edit->Paste).Reparequeodiretóriotarefasfoicriado.

13.9EXERCÍCIOS:DEPLOYCOMWAR 205

Page 215: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

PodemosacessaroprojetoatravésdaURL:http://localhost:8080/tarefas/loginForm

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

13.10 DISCUSSÃO EM AULA: LIDANDO COM DIFERENTES NOMESDECONTEXTO

Agoraéamelhorhoradeaprenderalgonovo

206 13.10DISCUSSÃOEMAULA:LIDANDOCOMDIFERENTESNOMESDECONTEXTO

Page 216: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO14

"É uma experiência eterna de que todos os homens com poder são tentados a abusar." -- Baron deMontesquieu

Nestecapítulo,vocêaprenderáa:

EntenderadiferençaentreaJPAeoHibernate;UsaraferramentadeORMJPAcomHibernate;Gerarastabelasemumbancodedadosqualquerapartirdesuasclassesdemodelo;InserirecarregarobjetospeloJPAnobanco;BuscarváriosobjetospeloJPA;

Com a popularização do Java em ambientes corporativos, logo se percebeu que grande parte dotempo do desenvolvedor era gasto na codificação de queries SQL e no respectivo código JDBCresponsávelportrabalharcomelas.

Alémdeumproblemadeprodutividade,algumasoutraspreocupaçõesaparecem:SQLque,apesarde ter umpadrãoANSI, apresenta diferenças significativas dependendodo fabricante.Não é simplestrocarumbancodedadospelooutro.

Há ainda amudança do paradigma.A programação orientada a objetos diferemuito do esquemaentidade relacional e precisamos pensar das duas maneiras para fazer um único sistema. Pararepresentarmosasinformaçõesnobanco,utilizamostabelasecolunas.Astabelasgeralmentepossuemchave primária (PK) e podem ser relacionadas pormeio da criação de chaves estrangeiras (FK) emoutrastabelas.

Quando trabalhamos com uma aplicação Java, seguimos o paradigma orientado a objetos, onderepresentamos nossas informações por meio de classes e atributos. Além disso, podemos utilizartambémherança,composiçãopararelacionaratributos,polimorfismo,enumerações,entreoutros.Esseburaco entre esses dois paradigmas gera bastante trabalho: a todo momento devemos "transformar"objetosemregistroseregistrosemobjetos.

UMAINTRODUÇÃOPRÁTICAAOJPACOMHIBERNATE

14.1MAPEAMENTOOBJETORELACIONAL

14UMAINTRODUÇÃOPRÁTICAAOJPACOMHIBERNATE 207

Page 217: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

Ferramentas para auxiliar nesta tarefa tornaram-se populares entre os desenvolvedores Java e sãoconhecidas como ferramentas de mapeamento objeto-relacional (ORM). O Hibernate é umaferramentaORM open source e é a líder demercado, sendo a inspiração para a especificação JavaPersistenceAPI (JPA).OHibernatenasceu semJPAmashoje emdia é comumacessaroHibernatepela especificação JPA. Como toda especificação, ela deve possuir implementações. Entre asimplementaçõesmaiscomuns,podemoscitar:HibernatedaRedHat,EclipseLinkdaEclipseFoundationeoOpenJPAdaApache.ApesardoHibernate teroriginadoa JPA,oEclipseLinkéa implementaçãoreferencial.

OHibernate abstrai o seu códigoSQL, toda a camada JDBC e o SQL será gerado em tempo deexecução.Maisque isso,elevaigeraroSQLqueserveparaumdeterminadobancodedados, jáquecadabancofalaum"dialeto"diferentedessalinguagem.AssimhátambémapossibilidadedetrocardebancodedadossemterdealterarcódigoJava,jáqueissoficacomoresponsabilidadedaferramenta.

Comousaremos JPAabstraímosmais ainda, podemosdesenvolver semconhecerdetalhes sobreoHibernateeatétrocaroHibernatecomumaoutraimplementaçãocomoOpenJPA:

VamosusaroJPAcomHibernate,ouseja,precisamosbaixarosJARsnositedoHibernate.Ositeoficial do Hibernate é o www.hibernate.org, onde você baixa a última versão na seção ORM eDownload.

Com o ZIP baixado emmãos, vamos descompactar o arquivo. Dessa pasta vamos usar todos osJARsobrigatórios(required).NãopodemosesqueceroJARdaespecificaçãoJPAqueseencontrana

EditoraCasadoCódigocomlivrosdeumaformadiferente

14.2JAVAPERSISTENCEAPIEFRAMEWORKSORM

14.3BIBLIOTECASDOHIBERNATEEJPA

208 14.2JAVAPERSISTENCEAPIEFRAMEWORKSORM

Page 218: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

pastajpa.

ParausaroHibernateeJPAnoseuprojetoénecessáriocolocartodosessesJARsnoclasspath.

OHibernate vai gerar o código SQL para qualquer banco de dados. Continuaremos utilizando obancoMySQL,portantotambémprecisamosoarquivo.jarcorrespondenteaodriverJDBC.

Paraestecapítulo,continuaremosutilizandoaclassequerepresentaumatarefa:

packagebr.com.caelum.tarefas.modelo;

publicclassTarefa{privateLongid;privateStringdescricao;privatebooleanfinalizado;privateCalendardataFinalizacao;}

Criamososgetterse settersparamanipularoobjeto,mas fiqueatentoquesódevemosusaressesmétodosserealmentehouvernecessidade.

EssaéumaclassecomoqualqueroutraqueaprendemosaescreveremJava.PrecisamosconfiguraroHibernateparaqueelesaibadaexistênciadessaclassee,destaforma,saibaquedeveinserirumalinhanatabelaTarefatodavezqueforrequisitadoqueumobjetodessetiposejasalvo.Emvezdeusarmos

otermo"configurar",falamosemmapearumaclasseatabela.

Para mapear a classe Tarefa , basta adicionar algumas poucas anotações em nosso código.AnotaçãoéumrecursodoJavaquepermite inserirmetadadosemrelaçãoanossaclasse,atributosemétodos.Essasanotaçõesdepoispoderãoserlidasporframeworksebibliotecas,paraqueelestomemdecisõesbaseadasnessaspequenasconfigurações.

Paraessanossaclasseemparticular,precisamosdeapenasquatroanotações:

@EntitypublicclassTarefa{

@Id@GeneratedValueprivateLongid;

privateStringdescricao;privatebooleanfinalizado;

@Temporal(TemporalType.DATE)privateCalendardataFinalizacao;

//métodos...}

14.4 MAPEANDO UMA CLASSE TAREFA PARA NOSSO BANCO DEDADOS

14.4MAPEANDOUMACLASSETAREFAPARANOSSOBANCODEDADOS 209

Page 219: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

@Entity indicaqueobjetosdessaclassesetornem"persistível"nobancodedados.@Id indica

queoatributoid énossachaveprimária (vocêprecisa terumachaveprimáriaem todaentidade)e

@GeneratedValuedizquequeremosqueestachavesejapopuladapelobanco(istoé,quesejausado

umautoincrementousequence,dependendodobancodedados).Com@Temporalconfiguramos

comomapearumCalendarparaobanco,aquiusamosapenasadata(semhora),maspoderíamoster

usado apenas a hora (TemporalType.TIME) ou timestamp (TemporalType.TIMESTAMP ). Essas

anotaçõesprecisamdosdevidosimports,epertencemaopacotejavax.persistence.

Masemquetabelaessaclasseserágravada?Emquaiscolunas?Quetipodecoluna?Naausênciadeconfiguraçõesmais específicas, oHibernate vai usar convenções: a classeTarefa será gravada na

tabela de nome tambémTarefa, e o atributo descricao em uma coluna de nome descricao

também!

Se quisermos configurações diferentes das convenções, basta usarmos outras anotações, que sãocompletamente opcionais. Por exemplo, para mapear o atributo dataFinalizacao numa coluna

chamadadata_finalizadofaríamos:

@Column(name="data_finalizado",nullable=true)privateCalendardataFinalizacao;

Parausarumatabelacomonometarefas:

@Entity@Table(name="tarefas")publicclassTarefa{

Reparequenasentidadeshátodasasinformaçõessobreastabelas.Baseadonelaspodemosatépedirgerarastabelasnobanco,masparaissoéprecisoconfiguraroJPA.

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

JáconheceoscursosonlineAlura?

210 14.4MAPEANDOUMACLASSETAREFAPARANOSSOBANCODEDADOS

Page 220: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

EmqualbancodedadosvamosgravarnossasTarefass?Qualéologin?Qualéasenha?OJPA

necessitadessasconfigurações,eparaissocriaremosoarquivopersistence.xml.

AlgunsdadosquevãonessearquivosãoespecíficosdoHibernateepodemserbemavançados,sobrecontroledecache,transações,connectionpooletc,tópicosquesãoabordadosnocursoFJ-25.

Paranossosistema,precisamosdequatro linhascomconfiguraçõesque jáconhecemosdoJDBC:string de conexão com o banco, o driver, o usuário e senha. Além dessas quatro configurações,precisamos dizer qual dialeto de SQL deverá ser usado nomomento que as queries são geradas; nonosso caso, MySQL. Vamos também mostrar o SQL no console para acompanhar o trabalho doHibernate.

Vamostambémconfiguraracriaçãodastabelasbaseadonasentidades.

Segueumaconfiguraçãocompletaquedefineumaunidadedepersistência(persistence-unit)comonometarefas,seguidospeladefiniçãodoprovedor,entidadeseproperties:

<persistencexmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"version="2.0">

<persistence-unitname="tarefas">

<!--provedor/implementacaodoJPA--><provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

<!--entidademapeada--><class>br.com.caelum.tarefas.modelo.Tarefa</class>

<properties><!--dadosdaconexao--><propertyname="javax.persistence.jdbc.driver"value="com.mysql.jdbc.Driver"/><propertyname="javax.persistence.jdbc.url"value="jdbc:mysql://localhost/fj21"/><propertyname="javax.persistence.jdbc.user"value="root"/><propertyname="javax.persistence.jdbc.password"value="<SENHADOBANCOAQUI>"/>

<!--propriedadesdohibernate--><propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQL8Dialect"/><propertyname="hibernate.show_sql"value="true"/><propertyname="hibernate.format_sql"value="true"/>

<!--atualizaobanco,geraastabelasseforpreciso--><propertyname="hibernate.hbm2ddl.auto"value="update"/></properties></persistence-unit></persistence>

14.5CONFIGURANDOOJPACOMASPROPRIEDADESDOBANCO

14.5CONFIGURANDOOJPACOMASPROPRIEDADESDOBANCO 211

Page 221: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

É importante saber que o arquivo persistence.xml deve ficar na pasta META-INF do seu

classpath.

ParausaroJPAnonossocódigoJava,precisamosutilizarsuaAPI.Elaébastantesimplesediretaerapidamentevocêestaráhabituadocomsuasprincipaisclasses.

Nosso primeiro passo é fazer com que o JPA leia a nossa configuração: tanto o nosso arquivopersistence.xmlquantoasanotaçõesquecolocamosnanossaentidadeTarefa.Paratal,usaremos

aclassecomomesmonomedoarquivoXML:Persistence.ElaéresponsáveldecarregaroXMLe

inicializarasconfigurações.ResultadodessaconfiguraçãoéumaEntityManagerFactory:

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");

Estamosprontos para usar o JPA.Antes degravar umaTarefa, precisamosque exista a tabela

correspondentenonossobancodedados.Emvezdecriarmososcriptquedefineoschema(ouDDLdeum banco, data definition language) do nosso banco (os famosos CREATE TABLE ....) podemos

deixar isto a cargo do próprioHibernate. Ao inicializar a EntityManagerFactory também já será

geradaumatabelaTarefaspoisconfiguramosqueobancodeveseratualizadapelapropriedadedo

Hibernate:hbm2ddl.auto.

Caso você esteja fazendo esse passo de casa. É preciso baixar o ZIP do Hibernate ORM 5.x(http://hibernate.org),extraí-lo,ecopiartodososJARsdaspastaslib/requiredelib/jpa.

Paraessaaplicaçãousaremosasseguintesversões:

antlr-2.7.x.jarbyte-buddy-1.9.1x.jardom4j-2.1.x.jarhibernate-commons-annotations-5.1.x.Final.jarhibernate-core-5.4.x.Final.jarjavassist-3.24.x-GA.jarjavax.persistence-api-2.x.jarjaxb-runtime-2.3.x.jarjboss-transaction-api_1.2_spec-1.0.x.Final.jar

14.6USANDOOJPA

14.7 PARA SABER MAIS: CONFIGURANDO O JPA COM HIBERNATEEMCASA

212 14.6USANDOOJPA

Page 222: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

1. Vamosprepararnossoprojetofj21-tarefascomasdependênciasdoHibernate.

CopieosJARsdoHibernateparaapastaWebContent/WEB-INF/libdoseuprojetodessaforma:

Váatéodiretório21/projeto-tarefas/jpahibernate;

SelecionetodososJARs,cliquecomobotãodireitoeescolhaCopy(ouCTRL+C);

ColetodososJARsnapastaWebContent/WEB-INF/libdoprojetofj21-tarefas(CTRL+V)

2. AnoteaclasseTarefacomoumaentidadedebancodedados.Lembre-sequeessaéumaanotação

dopacotejavax.persistence.

Obs:Nãoapaguenenhumaanotação,apenasadicioneasanotaçõesdoJPA.

@EntitypublicclassTarefa{

}

Namesmaclasseanoteseuatributoidcomochaveprimáriaecomocampodegeraçãoautomática:

@Id@GeneratedValueprivateLongid;

Agora é precisomapear o atributo dataFinalizacao para gravar apenas a data (sem hora) no

banco:

@Temporal(TemporalType.DATE)privateCalendardataFinalizacao;

VocêpodetambémfazerocursodatadessaapostilanaCaelum

14.8 EXERCÍCIOS: CONFIGURANDOO JPA E GERANDOO SCHEMADOBANCO

14.8EXERCÍCIOS:CONFIGURANDOOJPAEGERANDOOSCHEMADOBANCO 213

Page 223: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

1. Cliquecomobotãodireitonapastasrcdoprojetodofj21-tarefaseescolhaNew->Folder.

EscolhaMETA-INFcomonomedessapasta.

Váaodiretório21/projeto-tarefas/jpahibernate e copieoarquivopersistence.xml para apastaMETA-INF.

O arquivo é apenas um esboço, falta configurar a unidade de persistência com o provedor,entidadesepropriedades.Adicionedentrodoelementopersistence:

<persistence-unitname="tarefas">

<provider>org.hibernate.ejb.HibernatePersistence</provider><class>br.com.caelum.tarefas.modelo.Tarefa</class>

<properties><propertyname="javax.persistence.jdbc.driver"value="com.mysql.jdbc.Driver"/><propertyname="javax.persistence.jdbc.url"value="jdbc:mysql://localhost/fj21"/><propertyname="javax.persistence.jdbc.user"value="root"/><propertyname="javax.persistence.jdbc.password"value=""/>

<propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQL8Dialect"/>

214 14.8EXERCÍCIOS:CONFIGURANDOOJPAEGERANDOOSCHEMADOBANCO

Page 224: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<propertyname="hibernate.show_sql"value="true"/><propertyname="hibernate.format_sql"value="true"/><propertyname="hibernate.hbm2ddl.auto"value="update"/></properties></persistence-unit>

Asduaspropriedadesshow_sqleformat_sqlfazemcomquetodoSQLgeradopeloHibernate

apareçanoconsole.

1. CrieaclasseGeraTabelasnopacotebr.com.caelum.tarefas.jpa.

packagebr.com.caelum.tarefas.jpa;

//importsomitidos

publicclassGeraTabelas{

publicstaticvoidmain(String[]args){EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");

factory.close();}}

1. CriesuatabelaexecutandoaclasseGeraTabelas.Paraisso,cliquedadireitanocódigoeváem

RunAs->JavaApplication.

NãoéprecisorodaroTomcatparaesseexercício.

2. Agora,abraumanovaabanoTerminaledigitemysql-uroot se nãohouver senhadobanco, oumysql-uroot-p,sehouversenha,informandoasenhacorretaemseguida.Apósisto,digiteusefj21;e em seguida, show tables;. Se seu banco de dados já existia, e não foi preciso criá-lo no passoanterior,vocêvainotarapresençadeumatabelachamadatarefas.Nãoéestaatabelaquequeremos.ProcuramospelatabelaTarefa,comT,emmaiúsculo(igualaonomedaclasseTarefa).

3. (opcional)Casoalgumerrotenhaocorrido,épossívelqueoHibernatetenhalogadoumamensagem,mas você não a viu dado que oLog4J não está configurado.Mesmo que tudo tenha ocorrido demaneiracorreta,émuitoimportanteteroLog4Jconfigurado.

Paraisso,adicionenoarquivolog4j.propertiesdentrodapastasrc para que todoo logdo

nívelinfoouacimasejaenviadoparaoconsoleappenderdoSystem.out(defaultdoconsole):

14.8EXERCÍCIOS:CONFIGURANDOOJPAEGERANDOOSCHEMADOBANCO 215

Page 225: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

log4j.logger.org.hibernate=info

ParasecomunicarcomoJPA,precisamosdeumainstânciadeumobjetodotipoEntityManager.

AdquirimosumaEntityManageratravésdafábricajáconhecida:EntityManagerFactory.

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");

EntityManagermanager=factory.createEntityManager();

manager.close();factory.close();

AtravésdeumobjetodotipoEntityManager,épossívelgravarnovosobjetosnobanco.Paraisto,

bastautilizarométodopersistdentrodeumatransação:

Tarefatarefa=newTarefa();tarefa.setDescricao("EstudarJPA");tarefa.setFinalizado(true);tarefa.setDataFinalizacao(Calendar.getInstance());

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");EntityManagermanager=factory.createEntityManager();

manager.getTransaction().begin();manager.persist(tarefa);manager.getTransaction().commit();

System.out.println("IDdatarefa:"+tarefa.getId());

manager.close();

CUIDADOSAOUSAROJPA

AousaroJPAprofissionalmente,fiqueatentocomalgunscuidadosquesãosimples,masnãodada a devida atenção podem gerar gargalos de performance. Abrir EntityManager s

indiscriminadamenteéumdessesproblemas.EssepostdaCaelumindicaoutros:

http://bit.ly/bRc5g

EssesdetalhesdodiaadiaassimcomoJPAcomHibernateavançadosãovistosnocursoFJ-25daCaelum,deHibernateeJPAavançados.

Parabuscarumobjetodadasuachaveprimária,nocasooseuid,utilizamosométodofind,

14.9TRABALHANDOCOMOSOBJETOS:OENTITYMANAGER

Persistindonovosobjetos

Carregarumobjeto

216 14.9TRABALHANDOCOMOSOBJETOS:OENTITYMANAGER

Page 226: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

conformeoexemploaseguir:

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");EntityManagermanager=factory.createEntityManager();

Tarefaencontrada=manager.find(Tarefa.class,1L);

System.out.println(encontrada.getDescricao());

1. CrieumaclassechamadaAdicionaTarefanopacotebr.com.caelum.tarefas.jpa,elavaicriar

umobjetoeadicioná-loaobanco:

packagebr.com.caelum.tarefas.jpa;

//importsomitidos

publicclassAdicionaTarefa{

publicstaticvoidmain(String[]args){

Tarefatarefa=newTarefa();tarefa.setDescricao("EstudarJPAeHibernate");tarefa.setFinalizado(true);tarefa.setDataFinalizacao(Calendar.getInstance());

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");EntityManagermanager=factory.createEntityManager();

manager.getTransaction().begin();manager.persist(tarefa);manager.getTransaction().commit();

System.out.println("IDdatarefa:"+tarefa.getId());

manager.close();}}

1. RodeaclasseAdicionaTarefaeadicionealgumastarefasnobanco.Saídapossível:

2. Verifiqueosregistrosnobanco,seconectecomoclientedomysql:

mysql-urootusefj21;select*fromTarefa;

14.10EXERCÍCIOS:GRAVANDOECARREGANDOOBJETOS

14.10EXERCÍCIOS:GRAVANDOECARREGANDOOBJETOS 217

Page 227: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Sehouversenhanobanco, troqueoprimeirocomandopormysql-uroot-p, usando a senha

corretaprobanco.RodenovamenteaclasseAdicionaTarefaeverifiqueobanco.

1. Vamoscarregartarefaspelachaveprimária.

CrieumaclassechamadaCarregaTarefanopacotebr.com.caelum.tarefas.jpa:

packagebr.com.caelum.tarefas.jpa;

//importsomitidos

publicclassCarregaTarefa{

publicstaticvoidmain(String[]args){

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");EntityManagermanager=factory.createEntityManager();

Tarefaencontrada=manager.find(Tarefa.class,1L);System.out.println(encontrada.getDescricao());

manager.close();}}

1. RodeaclasseCarregaTarefaeverifiqueasaída.

Casorecebeuumaexception,verifiqueoiddatarefa.Eledeveexistirnobanco.

218 14.10EXERCÍCIOS:GRAVANDOECARREGANDOOBJETOS

Page 228: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Remover e atualizar os objetos com JPA também é muito simples. O EntityManager possui

métodosparacadaoperação.Pararemoveréprecisocarregaraentidadeantesedepoisusarométodoremove:

EntityManagermanager=//abrirumEntityManagerTarefaencontrada=manager.find(Tarefa.class,1L);

manager.getTransaction().begin();manager.remove(encontrada);manager.getTransaction().commit();

Paraatualizarumentidadequejápossuiumidexisteométodomerge,porexemplo:

Tarefatarefa=newTarefa();tarefa.setId(2);//esseidjáexistenobancotarefa.setDescricao("EstudarJPAeHibernate");tarefa.setFinalizado(false);tarefa.setDataFinalizacao(null);

EntityManagermanager=//abrirumEntityManager

manager.getTransaction().begin();manager.merge(tarefa);manager.getTransaction().commit();

OJPApossuiumalinguagemprópriadequeriesparafacilitarabuscadeobjetoschamadadeJPQL.Ocódigoaseguirmostraumapesquisaqueretornatodasastarefasnãofinalizadas:

EntityManagermanager=//abrirumEntityManagerList<Tarefa>lista=manager.createQuery("selecttfromTarefaastwheret.finalizado=false")

Seuslivrosdetecnologiaparecemdoséculopassado?

14.11REMOVENDOEATUALIZANDOOBJETO

14.12BUSCANDOCOMUMACLÁUSULAWHERE

14.11REMOVENDOEATUALIZANDOOBJETO 219

Page 229: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

.getResultList();

for(Tarefatarefa:lista){System.out.println(tarefa.getDescricao());}

Também podemos passar um parâmetro para a pesquisa. Para isso, é preciso trabalhar com umobjetoquerepresentaapesquisa(javax.persistence.Query):

EntityManagermanager=//abrirumEntityManager

Queryquery=manager.createQuery("selecttfromTarefaast"+"wheret.finalizado=:paramFinalizado");query.setParameter("paramFinalizado",false);

List<Tarefa>lista=query.getResultList();

Esteéapenasocomeço.OJPAémuitopoderosoe,nocursoFJ-25,veremoscomofazerqueriescomplexas,comjoins,agrupamentos,projeções,demaneiramuitomaissimplesdoquesetivéssemosdeescreverasqueries.Alémdisso,oJPAcomHibernateémuitocustomizável:podemosconfigurá-loparaquegereasqueriesdeacordocomdicasnossas,dessaformaotimizandocasosparticularesemqueasqueriesqueelegeraporpadrãonãosãodesejáveis.

UmaconfusãoquepodeserfeitaaprimeiravistaépensarqueoJPAcomHibernateélento,pois,eleprecisagerarasnossasqueries,lerobjetosesuasanotaçõeseassimpordiante.Naverdade,oHibernatefazumasériedeotimizaçõesinternamentequefazemcomqueoimpactodessastarefassejapróximoanada.Portanto,oHibernateé,sim,performático,ehojeemdiapodeserutilizadoemqualquerprojetoquesetrabalhacombancodedados.

1. CrieumaclassechamadaBuscaTarefasnopacotebr.com.caelum.tarefas.jpa:

Cuidado,aclasseQueryvemdopacotejavax.persistence:

packagebr.com.caelum.tarefas.jpa;

importjavax.persistence.Query;//outrosimportsomitidos

publicclassBuscaTarefas{

publicstaticvoidmain(String[]args){

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");EntityManagermanager=factory.createEntityManager();

//cuidado,useoimportjavax.persistence.QueryQueryquery=manager.createQuery("selecttfromTarefaast"+"wheret.finalizado=:paramFinalizado");

14.13EXERCÍCIOS:BUSCANDOCOMJPQL

220 14.13EXERCÍCIOS:BUSCANDOCOMJPQL

Page 230: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

query.setParameter("paramFinalizado",true);

List<Tarefa>lista=query.getResultList();

for(Tarefat:lista){System.out.println(t.getDescricao());}

manager.close();}}

1. RodeaclasseBuscaTarefaseverifiqueasaída.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Agoraéamelhorhoradeaprenderalgonovo

14.13EXERCÍCIOS:BUSCANDOCOMJPQL 221

Page 231: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO15

"Anucaéummistérioparaavista."--PaulValéry

O curso FJ-21, Java para desenvolvimento Web, procura abordar as principais tecnologias domercadoWebemJavadesdeseusfundamentosatéosframeworksmaisusados.

Maseagora,paraondedirecionarseusestudosesuacarreira?

Ospróximoscapítulosdaapostilasãoapêndicesextrasparaexpandirseuestudoemalgumasáreasquepodemserdeseuinteresse:

JPAeSpring-MostracomointegrarJPAcomSpringparautilizarJPAnacamadadepersistêncianoprojetofj21-tarefas.

TópicosdaServletAPI-AbordaváriostópicossobreServletseJSPsquenãoabordamosantes.São detalhes a mais e alguns recursos mais avançados. É interessante para expandir seuconhecimentoeajudarentendermelhoropadrãoServlets.

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

OmercadodeframeworksJavaéimenso.Hámuitasopçõesboasdisponíveisnomercadoemuitos

EAGORA?

15.1OSAPÊNDICESDESSAAPOSTILA

VocêpodetambémfazerocursodatadessaapostilanaCaelum

15.2FRAMEWORKSWEB

222 15EAGORA?

Page 232: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

pontosaconsiderarnaadoçãoouestudodealgumnovoframework.

OStrutscomcertezaéoframeworkcommaiorunanimidadenomercado,emespecialporcausadesuaversão1.x.Aversão2.0nãotemtantaforçamaséumdosmaisimportantes.

OVRaptor,criadonaUSPem2004emantidohojepelaCaelumeporumagrandecomunidade,não tem o tamanho do mercado de outros grandes frameworks. Mas tem a vantagem da extremasimplicidadeegrandeprodutividade,alémdeserbemfocadonomercadobrasileiro,comdocumentaçãoemportuguêsemuitomaterialdisponível.ACaeluminclusivedisponibilizaumcursodeVRaptor,oFJ-28quepossuisuaapostiladisponívelparadownloadgratuitonaInternetem:

http://www.caelum.com.br/apostilas

Um dos frameworks mais usados hoje é o JavaServer Faces - JSF. Seu grande apelo é ser oframeworkoficialdoJavaEEparaWeb,enquantoquetodososoutrossãodeterceiros.OJSFtemaindamuitascaracterísticasdiferentesdoStrutsoudoVRaptorquevimosnessecurso.

Emespecial,oJSFéditoumframeworkcomponent-based,enquantoqueStruts(1e2)eVRaptorsãoditosrequest-basedouaction-based.AideiaprincipaldeumframeworkdecomponenteséabstrairmuitosdosconceitosdaWebedoprotocoloHTTPprovendoumaformadeprogramaçãomaisparecidacomprogramaçãoparaDesktop.OJSFtemcomponentesvisuaisricosjáprontos,funcionaatravésdetratamentodeeventoseéstateful(aocontráriodaWeb"normal"ondetudoéstateless).NaCaelum,ocursoFJ-26tratadeJavaServerFaces:

http://www.caelum.com.br/curso/fj26

Maso JSFnão é único frameworkbaseado em componentes.Há outras opções (menos famosas)comooGoogleWebToolkit-GWTouoApacheWicket.Damesma forma,háoutros frameworksrequest-based alémdeStrutseVRaptor, comooStripesouoSpringMVC.NaCaelum,oSpring eSpringMVCétratadoemdetalhesnocursoFJ-27,juntocomoutrasfuncionalidadesdoSpring:

http://www.caelum.com.br/curso/fj27

Todaessapluralidadedeframeworkséboaparafomentarcompetiçãoeinovaçãonomercado,maspodeconfundirmuitooprogramadorqueestá iniciandonessemeio.Umbomcaminhoa seguir apósesse curso FJ-21 é continuar aprofundando seus conhecimentos no SpringMVC e noVRaptor (comajudadaapostilaaberta)epartirdepoisparaoestudodoJSF.Osoutros frameworksvocêvaiacabareventualmente encontrando algum dia em sua carreira, mas não se preocupe em aprender todos nocomeço.

Quando falamos de frameworks voltados para persistência e bancos de dados, felizmente, não há

15.3FRAMEWORKSDEPERSISTÊNCIA

15.3FRAMEWORKSDEPERSISTÊNCIA 223

Page 233: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

tanta dúvida quanto no mundo dos frameworksWeb. OHibernate é praticamente unanimidade nomercadoJava,principalmenteseusadocomoimplementaçãodaJPA.Háoutraspossibilidades,comooToplink, o EclipseLink, oOpenJPA, oDataNucleus, o JDO, o iBatis etc.Mas oHibernate é omaisimportante.

NaCaelum,abordamosJPAeHibernateavançadonocursoFJ-25:

http://www.caelum.com.br/curso/fj25

HáaindalivrosedocumentaçõesdisponíveissobreHibernate.RecomendamosfortementequevocêaprofundeseusestudosnoHibernatequeémuitousadoepedidonomercadoJavahoje.

ACaelumdisponibiliza para downloadgratuito algumasdas apostilas de seus treinamentos.Vocêpodebaixardiretonosite:

http://www.caelum.com.br/apostilas

OBlogdaCaeluméaindaoutraformadeacompanharnovidadeseexpandirseusconhecimentos:

http://blog.caelum.com.br

Diversasrevistas,noBrasilenoexterior,estudamomundoJavacomoninguémepodemajudaroinicianteaconhecermuitodoqueestáacontecendoláforanasaplicaçõescomerciais.

LembrandoqueaeditoraCasadoCódigopossuilivrosdeJSFeJPAquepodemteauxiliartambémnacontinuaçãoereforçodosseusestudos:

http://www.CasaDoCodigo.com.br

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

15.4ONDESEGUIRSEUSESTUDOS

Seuslivrosdetecnologiaparecemdoséculopassado?

224 15.4ONDESEGUIRSEUSESTUDOS

Page 234: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO16

"Ocaminhodoinfernoestápavimentadodeboasintenções."--Marx

Nestecapítulo,vocêaprenderáa:

IntegrarJPAcomSpring;InjetaroEntityManagerdentrodoDAO;GerenciarastransaçõescomSpring;

DentreasdiversascaracterísticasdoSpringumadasquemaischamaaatençãoéaintegraçãonativacomdiversastecnologiasimportantesdomercado.PodemoscitaroHibernateeoJPA.

VimosqueoSpringéumcontainerquecontrolaobjetos(oucomponentes),administrandoociclodavidadeles, inclusive ligandounsaosoutros (amarrando-os).NocasodoJPA,queremosqueoSpringcuidedaaberturaedofechamentodaEntityManagerFactoryedoEntityManager.Comisso,todosos componentes do Spring podem receber como dependência um EntityManager , mas agora

controladopeloSpring.Novamenteaplicandoainversãodecontrole.

Mas a inversão de controle não se limita a inicialização de objetos. O Spring também tira dodesenvolvedoraresponsabilidadedecontrolaratransação.AodelegarocontroledoEntityManager

paraoSpring,eleconsegueabrirefechartransaçõesautomaticamente.

VejacomoéainicializaçãodoJPAsemaajudadoSpring:

EntityManagerFactoryfactory=Persistence.createEntityManagerFactory("tarefas");EntityManagermanager=factory.createEntityManager();

manager.getTransaction().begin();

//aquiusaoEntityManager

manager.getTransaction().commit();manager.close();

NessepequenotrechodecódigopodemosvercomoétrabalhosoinicializaroJPAmanualmente.É

APÊNDICE-INTEGRAÇÃODOSPRINGCOMJPA

16.1GERENCIANDOOENTITYMANAGER

16APÊNDICE-INTEGRAÇÃODOSPRINGCOMJPA 225

Page 235: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

precisoabrire fechar todosos recursospara realmentecomeçarausaroEntityManager.OSpring

deveassumiressasresponsabilidadesefacilitarassimousodoJPA.

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

Para integrar-se com o JPA, o Spring disponibiliza umBean que devemos cadastrar no arquivoXML. Ele representa a EntityManagerFactory, mas agora gerenciada pelo Spring. Ou seja, toda

inicializaçãodafábricaficaaoencargodoSpring:

<beanid="entityManagerFactory"class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><propertyname="dataSource"ref="mysqlDataSource"/><propertyname="jpaVendorAdapter"><beanclass="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/></property></bean>

ReparequeoBeandefineHibernate como implementaçãodoJPAe recebeamysqlDataSource

quejádefinimosanteriormentedentrodoXMLdoSpring.ComoanossaDatasourcejásabeosdados

dodriver,loginesenha,oarquivopersistence.xmldoJPAtambémficamaissimples:

<persistencexmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistencehttp://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"version="2.0">

<persistence-unitname="tarefas">

<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

<class>br.com.caelum.tarefas.modelo.Tarefa</class>

<properties>

JáconheceoscursosonlineAlura?

16.2CONFIGURANDOOJPANOSPRING

226 16.2CONFIGURANDOOJPANOSPRING

Page 236: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<!--SEMaspropriedadesURL,login,senhaedriver-->

<propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQL5InnoDBDialect"/><propertyname="hibernate.show_sql"value="true"/><propertyname="hibernate.format_sql"value="true"/><propertyname="hibernate.hbm2ddl.auto"value="update"/></properties></persistence-unit>

</persistence>

ComJPAconfiguradopodemosaproveitarainversãodecontroleeinjetaroEntityManagerdentro

dequalquercomponenteadministradopeloSpring.

VamoscriarumaclasseJpaTarefaDao para usar oEntityManager.A classeJpaTarefaDao

precisadoEntityManager.ComoJPAéumaespecificação,oSpringtambémaproveitaumaanotação

deespecificaçãoparareceberadependência.Nessecasonãopodemosusaraanotação@Autowireddo

[email protected]ção@PersistenceContext não funciona

comconstrutores,exigindoumoutropontodeinjeção.Usaremosoatributoparadeclararadependência:

@RepositorypublicclassJpaTarefaDao{

@PersistenceContextprivateEntityManagermanager;

//semconstrutor

//aquivemosmétodos}

Nos métodos do JpaTarefaDao faremos o uso do EntityManager usando os métodos já

conhecidoscomopersist(..)parapersistirumatarefaouremove(..)pararemover:

@RepositorypublicclassJpaTarefaDao{

@PersistenceContextprivateEntityManagermanager;

//semconstrutor

publicvoidadiciona(Tarefatarefa){manager.persist(tarefa);}

publicvoidaltera(Tarefatarefa){manager.merge(tarefa);}

publicList<Tarefa>lista(){

16.3INJETANDOOENTITYMANAGER

16.3INJETANDOOENTITYMANAGER 227

Page 237: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

returnmanager.createQuery("selecttfromTarefat").getResultList();}

publicTarefabuscaPorId(Longid){returnmanager.find(Tarefa.class,id);}

publicvoidremove(Tarefatarefa){TarefatarefaARemover=buscaPorId(tarefa.getId());manager.remove(tarefaARemover);}

publicvoidfinaliza(Longid){Tarefatarefa=buscaPorId(id);tarefa.setFinalizado(true);tarefa.setDataFinalizacao(Calendar.getInstance());manager.merge(tarefa);}}

A implementação do JpaTarefaDao ficou muito mais simples se comparada com o

JdbcTarefaDao,emalgunsmétodoséapenasumalinhadecódigo.

VoltandoparanossaclasseTarefasControllervamoslembrarqueinjetamosoJdbcTarefaDao

paratrabalharcomobancodedados:

@ControllerpublicclassTarefasController{

privatefinalJdbcTarefaDaodao;

@AutowiredpublicTarefasController(JdbcTarefaDaodao){this.dao=dao;}

@RequestMapping("mostraTarefa")publicStringmostra(Longid,Modelmodel){model.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/mostra";}

//outrosmétodosomitidos}

Quandoolhamosparaosmétodospropriamenteditos,porexemplo,mostra,percebemosqueoque

é realmente necessário para executá-lo é algum DAO. A lógica em si é independente da instânciaespecíficaqueestamosinstanciando,ousejaparaaclasseTarefasControllernãoimportaseestamos

usando JDBC ou JPA.Queremos um desacoplamento da implementação doDAO especifico, e algodevedecidirqualimplementaçãousaremosporbaixodospanos.

Oproblemadesse tipodechamadaéque,nodiaemqueprecisarmosmudara implementaçãodoDAO,precisaremosmudarnossaclasse.Agoraimaginequetenhamos10controladoresnosistemaque

16.4BAIXOACOPLAMENTOPELOUSODEINTERFACE

228 16.4BAIXOACOPLAMENTOPELOUSODEINTERFACE

Page 238: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

usem nosso JdbcTarefaDao. Se todas usam a implementação específica, quando formos mudar a

implementaçãoparausarJPAparapersistênciaporexemplo,digamos,JpaTarefaDao, precisaremos

mudaremvárioslugares.

OqueprecisamosentãoéapenasumaTarefaDaodentrodaclasseTarefasController, então

vamosdefinir(extrair)umanovainterfaceTarefaDao:

publicinterfaceTarefaDao{

TarefabuscaPorId(Longid);List<Tarefa>lista();voidadiciona(Tarefat);voidaltera(Tarefat);voidremove(Tarefat);voidfinaliza(Longid);}

EaclasseJdbcTarefaDaoimplementaráessainterface:

@RepositorypublicclassJdbcTarefaDaoimplementsTarefaDao{

//implementaçãodonossodaousandojdbc}

Dessa maneira vamos injetar uma implementação compatível com a interface dentro da classeTarefasController

@ControllerpublicclassTarefasController{

privateTarefaDaodao;//usandoainterfaceapenas!

@AutowiredpublicTarefasController(TarefaDaodao){this.dao=dao;}

//métodosomitidos}

Agora a vantagem dessa abordagem é que podemos usar uma outra implementação da interfaceTarefaDaosemalteraraclasseTarefasController,nonossocasovamosusarJpaTarefaDao:

@RepositorypublicclassJpaTarefaDaoimplementsTarefaDao{

@PersistenceContextEntityManagermanager;

//semconstrutor

//métodosomitidos}

Repare que o DAO também vai implementar a interface TarefaDao . Assim temos duas

16.4BAIXOACOPLAMENTOPELOUSODEINTERFACE 229

Page 239: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

implementaçõesdamesmainterface:

Como o Spring não sabe qual das duas implementações deve ser utilizada é preciso qualificar adependência:

@ControllerpublicclassTarefasController{

privateTarefaDaodao;//usaapenasainterface!

@Autowired@Qualifier("jpaTarefaDao")publicTarefasController(TarefaDaodao){this.dao=dao;}

//métodosomitidos}

DessamaneiraoSpringinjetaráoJpaTarefaDao.

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

Paraosuporteà transaçãoserativadoprecisamosfazerduasconfiguraçõesnoXMLdoSpring.Aprimeiraéhabilitarogerenciadordetransação(TransactionManager).Porém,comooSpringpodecontrolar JPA, Hibernate e outros, devemos configurar o gerenciador exatamente para uma dessastecnologias. No caso do JPA, a única dependência que o JpaTransactionManager precisa é uma

entityManagerFactory:

<beanid="transactionManager"

VocêpodetambémfazerocursodatadessaapostilanaCaelum

16.5GERENCIANDOATRANSAÇÃO

230 16.5GERENCIANDOATRANSAÇÃO

Page 240: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

class="org.springframework.orm.jpa.JpaTransactionManager"><propertyname="entityManagerFactory"ref="entityManagerFactory"/></bean>

entityManagerFactoryéonomedoBeanconfiguradoanteriormente:

Asegundaparteéavisarqueocontroledetransaçõesseráfeitoviaanotação,parecidocomaformadehabilitarousodeanotaçõesparaoSpringMVC.

<tx:annotation-driven/>

Por fim, podemos usar o gerenciamento da transação dentro das nossas classes. Aqui ficamuitosimples,ésóusaraanotação@Transactionalnométodoqueprecisadeumatransação,porexemplo

nométodoadicionadaclasseTarefasController:

@Transactional@RequestMapping("adicionaTarefa")publicStringadiciona(@ValidTarefatarefa,BindingResultresult){

if(result.hasFieldErrors("descricao")){return"tarefa/formulario";}

dao.adiciona(tarefa);return"redirect:listaTarefas";}

Amesma anotação também pode ser utilizada na classe. Isso significa que todos osmétodos daclasseserãoexecutadosdentrodeumatransação:

@Transactional@ControllerpublicclassTarefasController{

Repareaquiabelezadainversãodecontrole.Nãohánecessidadedechamarbegin(),commit()

ourollback(),bastausar@Transactional eoSpringassumea responsabilidadeemgerenciar a

transação.

Há um problema ainda, usando o gerenciamento de transação pelo Spring exige a presença doconstrutorpadrãosemparâmetros.Vamostrocaraquitambémopontodeinjeçãodoconstrutorparaoatributo.Aclassecompletaficacomo:

packagebr.com.caelum.tarefas.controller;

//imports

@Controller@TransactionalpublicclassTarefasController{

@AutowiredTarefaDaodao;

@RequestMapping("novaTarefa")publicStringform(){

16.5GERENCIANDOATRANSAÇÃO 231

Page 241: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

return"tarefa/formulario";}

@RequestMapping("adicionaTarefa")publicStringadiciona(@ValidTarefatarefa,BindingResultresult){

if(result.hasFieldErrors("descricao")){return"tarefa/formulario";}

dao.adiciona(tarefa);return"tarefa/adicionada";}

@RequestMapping("listaTarefas")publicStringlista(Modelmodel){model.addAttribute("tarefas",dao.lista());return"tarefa/lista";}

@RequestMapping("removeTarefa")publicStringremove(Tarefatarefa){dao.remove(tarefa);return"redirect:listaTarefas";}

@RequestMapping("mostraTarefa")publicStringmostra(Longid,Modelmodel){model.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/mostra";}

@RequestMapping("alteraTarefa")publicStringaltera(Tarefatarefa){dao.altera(tarefa);return"redirect:listaTarefas";}

@RequestMapping("finalizaTarefa")publicStringfinaliza(Longid,Modelmodel){dao.finaliza(id);model.addAttribute("tarefa",dao.buscaPorId(id));return"tarefa/finalizada";}}

1. VamosusarJPAatravésdoSpring.ParaissoéprecisocopiarosJARseguintes:

spring-orm-5.2.x.RELEASE.jar

spring-tx-5.2.x.RELEASE.jar

Paraisso:

VáaoDesktop,eentrenodiretório21/projeto-tarefas/springjpa.Copie os JARs ( CTRL+C ) e cole-o ( CTRL+V ) dentro de workspace/fj21-

16.6EXERCÍCIOS:INTEGRANDOJPACOMSPRING

232 16.6EXERCÍCIOS:INTEGRANDOJPACOMSPRING

Page 242: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

tarefas/WebContent/WEB-INF/lib

2. No projeto fj21-tarefas , vá a pasta WebContent/WEB-INF e abra o arquivo spring-

context.xml.

NeleéprecisodeclararoentityManagerFactoryeogerenciadordetransações.

Você pode copiar essa parte do XML do arquivo Caelum/21/apendice/spring-context-

confs.xml.Copieoconteúdodoarquivoecoledentrodospring-context.xml:

<!--gerenciamentodejpapelospring--><beanid="entityManagerFactory"class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><propertyname="dataSource"ref="mysqlDataSource"/><propertyname="jpaVendorAdapter"><beanclass="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/></property></bean>

<!--gerenciamentodatransaçãopelospring--><beanid="transactionManager"class="org.springframework.orm.jpa.JpaTransactionManager"><propertyname="entityManagerFactory"ref="entityManagerFactory"/></bean>

<tx:annotation-driven/>

Comessasdeclarações,SpringgerenciaaEntityManagerFactoryehabilitaogerenciamentode

transações. Podemos também remover ou comentar as configurações de conexão nopersistence.xml:

<persistence-unitname="tarefas">

<provider>org.hibernate.ejb.HibernatePersistence</provider><class>br.com.caelum.tarefas.modelo.Tarefa</class>

<properties><!--<propertyname="javax.persistence.jdbc.driver"value="com.mysql.jdbc.Driver"/><propertyname="javax.persistence.jdbc.url"value="jdbc:mysql://localhost/fj21"/><propertyname="javax.persistence.jdbc.user"value="root"/><propertyname="javax.persistence.jdbc.password"value=""/>-->

<propertyname="hibernate.dialect"value="org.hibernate.dialect.MySQL8Dialect"/><propertyname="hibernate.show_sql"value="true"/><propertyname="hibernate.format_sql"value="true"/><propertyname="hibernate.hbm2ddl.auto"value="update"/></properties></persistence-unit>

1. O próximo passo é criar a interface TarefaDao. Crie uma nova interface dentro do package

br.com.caelum.tarefas.dao:

16.6EXERCÍCIOS:INTEGRANDOJPACOMSPRING 233

Page 243: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

packagebr.com.caelum.tarefas.dao;

//importsomitidos

publicinterfaceTarefaDao{

TarefabuscaPorId(Longid);List<Tarefa>lista();voidadiciona(Tarefat);voidaltera(Tarefat);voidremove(Tarefat);voidfinaliza(Longid);}

1. Crie uma classe JpaTarefaDao que recebe o EntityManager . Implemente a interface

TarefaDaocomtodososmétodos.

packagebr.com.caelum.tarefas.dao;

//importsomitidos

@RepositorypublicclassJpaTarefaDaoimplementsTarefaDao{

@PersistenceContextEntityManagermanager;

//semconstrutor

publicvoidadiciona(Tarefatarefa){manager.persist(tarefa);}

publicvoidaltera(Tarefatarefa){manager.merge(tarefa);}

publicList<Tarefa>lista(){returnmanager.createQuery("selecttfromTarefat").getResultList();}

publicTarefabuscaPorId(Longid){returnmanager.find(Tarefa.class,id);}

publicvoidremove(Tarefatarefa){TarefatarefaARemover=buscaPorId(tarefa.getId());manager.remove(tarefaARemover);}

publicvoidfinaliza(Longid){Tarefatarefa=buscaPorId(id);tarefa.setFinalizado(true);tarefa.setDataFinalizacao(Calendar.getInstance());}}

1. AgorafaçacomqueaclasseJdbcTarefaDaoimplementeainterfaceTarefaDao, adaptandoos

métodosexistentescasosejanecessário:

234 16.6EXERCÍCIOS:INTEGRANDOJPACOMSPRING

Page 244: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

@RepositorypublicclassJdbcTarefaDaoimplementsTarefaDao{

//implementaçãodonossodaousandojdbc}

1. Altere a classe TarefasController , use a interface TarefaDao apenas. Assim a classe

TarefasControllerficadesacopladodaimplementação.Nãoesquecedeapagaroconstrutor:

@ControllerpublicclassTarefasController{

@AutowiredTarefaDaodao;//usaapenasainterface!

//semconstrutor

//métodosomitidos,semmudança}

1. Como temos dois possíveis candidatos para o processo de injeção que implementam a interfaceTarefaDaooSpringnãosabequalescolher.Temosqueadicionarumqualificadorna injeçãoda

dependênciaquediráqualimplementaçãoqueremosusar:

@Autowired@Qualifier("jpaTarefaDao")TarefaDaodao;//usaapenasainterface!

1. Por fim, vamos habilitar o gerenciamento de transação para qualquer método da classeTarefasController.

Abra a classe e use a anotação @Transactional (do pacote

org.springframework.transaction.annotation)emcimadaclasse:

@Transactional@ControllerpublicclassTarefasController{

2. ReinicieoTomcateacesseaaplicaçãodetarefasemhttp://localhost:8080/fj21-tarefas/listaTarefas.

1. Podemos integrar a entidade User ao JPA, para isso primeiro temos que colocar as anotaçõesnecessáriasnanossaclassededomínio:

//importsomitidos

@EntitypublicclassUsuario{

@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;

16.7 EXERCÍCIOS OPCIONAIS: INTEGRANDO A ENTIDADE USERCOMOJPA

16.7EXERCÍCIOSOPCIONAIS:INTEGRANDOAENTIDADEUSERCOMOJPA 235

Page 245: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

//atributosemétodosomitidos}

1. AgoravamosdefinirumanovainterfacechamadaUsuarioDao:

packagebr.com.caelum.tarefas.dao;

importbr.com.caelum.tarefas.modelo.Usuario;

publicinterfaceUsuarioDao{publicbooleanexisteUsuario(Usuariousuario);}

1. DiremosqueaclasseJdbcUsuarioDaoimplementaessainterface:

//importsomitidos

@RepositorypublicclassJdbcUsuarioDaoimplementsUsuarioDao{//métodosomitidos}

1. AgoracriaremosaclasseJpaUsuarioDaoqueimplementaráainterfacequeacabamosdecriar:

packagebr.com.caelum.tarefas.dao;

importorg.springframework.stereotype.Repository;importbr.com.caelum.tarefas.modelo.Usuario;

@RepositorypublicclassJpaUsuarioDaoimplementsUsuarioDao{

@OverridepublicbooleanexisteUsuario(Usuariousuario){//TODOAuto-generatedmethodstubreturnfalse;}

}

Precisamos agora adaptar ométodoexisteUsuario daJdbcUsuarioDao para que ele use o

EntityManager . Faremos a injeção do EntityManager através da anotação

@PersistenceContext,emseguidamontaremosumaquerybuscaránobancodedadosumalista

deusuárioscomumlogineumasenhafixa:

@RepositorypublicclassJpaUsuarioDaoimplementsUsuarioDao{

@PersistenceContextEntityManagermanager;

@OverridepublicbooleanexisteUsuario(Usuariousuario){manager.createQuery("selectufromUsuariou"+"whereu.login=:loginandu.senha=:senha",Usuario.class).setParameter("login",usuario.getLogin()).setParameter("senha",usuario.getSenha())}

236 16.7EXERCÍCIOSOPCIONAIS:INTEGRANDOAENTIDADEUSERCOMOJPA

Page 246: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

}

Diremos ao JPA que queremos uma lista como resultado, adicionando o méotodogetResultList()ecapturaremosesseretornoemumavariávelchamadalistaDeUsuarios:

@RepositorypublicclassJpaUsuarioDaoimplementsUsuarioDao{

@PersistenceContextEntityManagermanager;

@OverridepublicbooleanexisteUsuario(Usuariousuario){List<Usuario>listaDeUsuarios=manager.createQuery("selectufromUsuariou"+"whereu.login=:loginandu.senha=:senha",Usuario.class).setParameter("login",usuario.getLogin()).setParameter("senha",usuario.getSenha()).getResultList();}}

SetivermospassadoascredenciaiscorretasdeumusuárioalistalistaDeUsuariosdeveráconteraomenos1registro,ouseja,devemosretornartrue;casonenhumusuáriosejaencontradoentãoa

listaévazia,eretornaremosfalse.Ométodocompletoficaráassim:

@PersistenceContextEntityManagermanager;

@OverridepublicbooleanexisteUsuario(Usuariousuario){List<Usuario>listaDeUsuarios=manager.createQuery("selectufromUsuariou"+"whereu.login=:loginandu.senha=:senha",Usuario.class).setParameter("login",usuario.getLogin()).setParameter("senha",usuario.getSenha()).getResultList();

if(listaDeUsuarios.isEmpty())returnfalse;elsereturntrue;}

1. AgoratemosquesubstuirnoLoginControlleraclassepelainterface,pedirparaoSpringfazera

injeção da dependência e auxiliar ele na escolha de qual implementação da interface deverá serusada,atravésdaanotação@Qualifier("jpaUsuarioDao"):

//importsomitidos

@ControllerpublicclassLoginController{

@Autowired@Qualifier("jpaUsuarioDao")privateUsuarioDaodao;

//métodosomitidos}

16.7EXERCÍCIOSOPCIONAIS:INTEGRANDOAENTIDADEUSERCOMOJPA 237

Page 247: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Caso a tabelaUsuario não exista, descomenteo código comentado empersistence.xml e

adicioneaclasseUsuario,deformasemelhanteaadiçãodaclasseTarefa

Paracadastrarumnovousuário,noterminalabertonomysql,useocomandoabaixo:

insertintoUsuario(login,senha)values('seu_usuario','sua_senha');

1. ReinicieoTomcatetenteselogarnaaplicaçãoemhttp://localhost:8080/fj21-tarefas/loginForm.

Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Seuslivrosdetecnologiaparecemdoséculopassado?

238 16.7EXERCÍCIOSOPCIONAIS:INTEGRANDOAENTIDADEUSERCOMOJPA

Page 248: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

CAPÍTULO17

"Measuring programming progress by lines of code is like measuring aircraft building progress byweight."--BillGates

Este capítulo aborda vários outros pequenos assuntos da Servlet API ainda não tratados, muitosdelesimportantesparaacertificaçãoSCWCD.

Podemosconfigurarnoweb.xmlalgunsparâmetrosquedepoisvamosleremnossaaplicação.Umaforma é passarmos parâmetros especificamente para uma Servlet ou um filtro usando a tag <init-

param>comonosexemplosabaixo:

<!--emservlet--><servlet><servlet-name>MinhaServlet</servlet-name><servlet-class>pacote.MinhaServlet</servlet-class><init-param><param-name>nome</param-name><param-value>valor</param-value></init-param></servlet>

<!--emfilter--><filter><filter-name>MeuFiltro</filter-name><filter-class>pacote.MeuFiltro</filter-class><init-param><param-name>nome</param-name><param-value>valor</param-value></init-param></filter>

Podemos, inclusive, ter vários parâmetros namesma servlet ou filtro.Depois, no código Java daServletoudofiltroespecífico,podemosrecuperaressesparâmetrosusando:

//emservletStringvalor=getServletConfig().getInitParameter("nome");

//emfiltro,noinitStringvalor=filterConfig.getInitParameter("nome")

Outra possibilidade é configurar parâmetros para o contexto inteiro e não apenas uma servletespecífica.Podemosfazerissocomatag<context-param>,comoabaixo:

APÊNDICE-TÓPICOSDASERVLETAPI

17.1INIT-PARAMSECONTEXT-PARAMS

17APÊNDICE-TÓPICOSDASERVLETAPI 239

Page 249: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

<context-param><param-name>nome</param-name><param-value>param</param-value></context-param>

E,nocódigoJavadeumaServlet,porexemplo:

Stringvalor=getServletContext().getInitParameter("nome");

Muitos frameworks usam parâmetros no web.xml para configurar. O VRaptor e o Spring sãoexemplosdeusodesse recurso.Maspodemosusar issoemnossas aplicações tambémpara retirardocódigoJavacertasconfiguraçõesparametrizáveis.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende

Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Épossívelconfigurarnoweb.xmlqualarquivodeveserchamadoquandoalguémacessarumaURLraiznoservidor,comoporexemplo:

http://localhost:8080/fj-21-agenda/http://localhost:8080/fj-21-agenda/uma-pasta/

Sãoosarquivosindexquenormalmenteusamosemoutrasplataformas.MasnoJavaEEpodemoslistarosnomesdearquivosquedesejamosque sejamoswelcomefiles.Basta defini-los noXMLeoservidorvaitentá-losnaordemdedeclaração:

<welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list>

Comodizerqualoencodingdenossosarquivosjspdeumamaneiraglobal?Comonosprotegerde

Agoraéamelhorhoradeaprenderalgonovo

17.2WELCOME-FILE-LIST

17.3PROPRIEDADESDEPÁGINASJSP

240 17.2WELCOME-FILE-LIST

Page 250: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

programadores iniciantes em nossa equipe e desabilitar o código scriptlet? Como adicionar um

arquivo antes e/ou depois de todos os arquivos JSPs? Ou de todos os JSPs dentro de determinadodiretório?

Pararesponderessaseoutrasperguntas,aAPIdejspresolveupossibilitardefiniralgumastagsnonossoarquivoweb.xml.

Porexemplo,paradesativarscripting(osscriptlets):

<scripting-invalid>true</scripting-invalid>

Ativarexpressionlanguage(quejávemativado):

<el-ignored>false</el-ignored>

Determinaroencodingdosarquivosdeumamaneiragenérica:

<page-encoding>UTF-8</page-encoding>

IncluirarquivosestaticamenteantesedepoisdeseusJSPs:

<include-prelude>/antes.jspf</include-prelude><include-coda>/depois.jspf</include-coda>

OcódigoaseguirmostracomoaplicartaiscaracterísticasparatodososJSPs,reparequeatagurl-

patterndeterminaogrupodearquivoscujosatributosserãoalterados:

<jsp-config><jsp-property-group><display-name>todososjsps</display-name><description>configuracoesdetodososjsps</description><url-pattern>*.jsp</url-pattern><page-encoding>UTF-8</page-encoding><scripting-invalid>true</scripting-invalid><el-ignored>false</el-ignored><include-prelude>/antes.jspf</include-prelude><include-coda>/depois.jspf</include-coda></jsp-property-group></jsp-config>

ExisteumamaneiraemumarquivoJSPdeincluirumoutroarquivoestaticamente.Istofazcomqueo arquivo a ser incluído seja literalmente copiado e colado dentro do seu arquivo antes da primeirainterpretação(compilação)doseujsp.

A vantagem é que como a inclusão é feita uma única vez antes do arquivo ser compilado, essainclusão é extremamente rápida, porém vale lembrar que o arquivo incluído pode ou não funcionarseparadamente.

<%@includefile="outra_pagina.jsp"%>

17.4INCLUSÃOESTÁTICADEARQUIVOS

17.4INCLUSÃOESTÁTICADEARQUIVOS 241

Page 251: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

ComotratarpossíveisexceptionsemnossapáginaJSP?NossosexercíciosdelistagemdecontatostantocomscriptletsquantocomJSTLusamoContatoDaoquepodelançarumaexceçãoseobancode

dadosestiverforadoar,porexemplo.Comotratar?

Se nosso JSP é um imenso scriptlet de código Java, o tratamento é o mesmo de códigos Javanormais:trycatch:

<html><%try{ContatoDaodao=newContatoDao();//...etc...}catch(Exceptionex){%>Ocorreualgumerroaoacessarobancodedados.<%}%></html>

Nãoparecemuitoelegante.Masequandousamostags,háumaformamelhor?Poderíamosusaratagc:catch,comomesmotipodeproblemadasoluçãoanterior:

<c:catchvar="error"><jsp:useBeanid="dao"class="br.com.caelum.jdbc.dao.ContatoDao"/><c:forEachvar="contato"items="${dao.lista}">....</c:forEach></c:catch><c:iftest="${notemptyerror}">Ocorreualgumerroaoacessarobancodedados.</c:if>

ReparequeaprópriaJSTLnosapresentaumasoluçãoquenãosemostraboaparaessetipodeerro

EditoraCasadoCódigocomlivrosdeumaformadiferente

17.5TRATAMENTODEERROEMJSP

242 17.5TRATAMENTODEERROEMJSP

Page 252: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

quequeremos tratar.É importantedeixarclaroquedesejamostrataro tipodeerroquenão temvolta,devemosmostrarumamensagemdeerroparaoclienteepronto,porexemploquandoaconexãocomobancocaiouquandoocorrealgumerronoservidor.

Quandoestávamos trabalhandocomServlets,haviauma solução simplese elegante:não tratar asexceçõesde formaespalhadamas simcriar umapágina centralizadade tratamentode erros.Naquelecaso,conseguimosissocomo<error-page>.

ComJSPs,conseguimosomesmoresultadomassemXML.UsamosumadiretivanotopodoJSPque indica qual é a página central de tratamento de erro. E nesse caso não precisamos nem detry/catchnemde<c:catch>:

<%@pageerrorPage="/erro.html"%>...<jsp:useBeanid="dao"class="br.com.caelum.jdbc.dao.ContatoDao"/>...

ParalertodososparâmetrosdorequestbastaacessarométodogetParameterMapdorequest.

Map<String,Object>parametros=request.getParameterMap();for(Stringparametro:parametros.keySet()){//facaalgocomoparametro}

ÀsvezesnãoésimplestrabalharcomlinkspoistemosquepensarnaURLqueoclienteacessaaovisualizaranossapágina.

AJSTLresolveesseproblema:supondoqueasuaaplicaçãosechamejspteste,ocódigoabaixo

geraastring/jspteste/imagem/banner.jpg.

<c:urlvalue="/imagem/banner.jpg"/>

Ébastanteútilaomontarmenusúnicosincluídosemváriaspáginasequeprecisamlidarcomlinksabsolutos.

17.6DESCOBRINDOTODOSOSPARÂMETROSDOREQUEST

17.7TRABALHANDOCOMLINKSCOMAC:URL

17.6DESCOBRINDOTODOSOSPARÂMETROSDOREQUEST 243

Page 253: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!

ConheçaoscursosonlineAlura.

SabemosquepodemosexecutarcódigonomomentoqueumaServletouumfiltrosãoinicializadosatravésdosmétodosinitdecadaumdeles.Masesequisermosexecutaralgonoiníciodaaplicação

Web(docontextoWeb),independentedetermosounãoServletefiltrosedonúmerodeles?

Paraissoexistemoscontextlisteners.VocêpodeescreverumaclasseJavacommétodosqueserãochamados automaticamente no momento que seu contexto for iniciado e depois desligado. Bastaimplementar a interface ServletContextListener e usar a tag <listener> no web.xml para

configurá-la.

Porexemplo:

publicclassMeuListenerimplementsServletContextAttributeListener{publicvoidcontextInitialized(ServletContextEventevent){System.out.println("Contextoiniciado...");}

publicvoidcontextDestroyed(ServletContextEventevent){System.out.println("Contextodesligado...");}}

EdepoisnoXML:

<listener><listener-class>pacote.MeuListener</listener-class></listener>

AsaplicaçõesWebemJavatêm3escopospossíveis.Jávimoseusamosdoisdeles:oderequesteodesessão.Podemoscolocarumatributonorequestcomrequest.setAttribute(..,..)eeleestará

JáconheceoscursosonlineAlura?

17.8CONTEXTLISTENER

17.9OSERVLETCONTEXTEOESCOPODEAPLICAÇÃO

244 17.8CONTEXTLISTENER

Page 254: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

disponívelparatodoorequest(desdeaActionatéoJSP,osfiltrosetc).

Da mesma forma, podemos pegar a HttpSession e colocar um atributo com

session.setAttribute(..,..) e ela estará disponível na sessãodaquele usuário através devários

requests.

Oterceiroescopoéumescopoglobal,ondeosobjetossãocompartilhadosnaaplicaçãointeira,portodos os usuários em todos os requests. É o chamado escopo de aplicação, acessível peloServletContext.

Podemos,emumaServlet,setaralgumatributousando:

getServletContext().setAttribute("nomeGlobal","valor");

Depois,podemosrecuperaressevalorcom:

Objectvalor=getServletContext().getAttribute("nomeGlobal");

Umbomusoécompartilharconfiguraçõesglobaisdaaplicação,comoporexemplousuárioesenhadeumbancodedados,oualgumobjetodecachecompartilhadoetc.Vocêpode,porexemplo,inicializaralgum objeto global usando um ServletContextListener e depois disponibilizá-lo no

ServletContextparaorestodaaplicaçãoacessar.

EcomofazemosparaacessaroescopodeaplicaçãononossoJSP?Simples,umadasvariáveisquejáexisteemumJSPsechamaapplication,algocomo:

ServletContextapplication=getServletContext();

Portantopodemosutilizá-laatravésdescriptlet:

<%=application.getAttribute("nomeGlobal")%><br/>

Como já vimos anteriormente, o código do tipo scriptlet pode sermaléfico para nossa aplicação,sendoassimvamosutilizarExpressionLanguageparaacessarumatributodoescopoaplicação:

AcessandocomEL:${nomeGlobal}<br/>

ReparequeaExpressionLanguageprocurarátalatributonãosónoescopodoapplication,como

veremosmaisafrente.Paradeixarclaroquevocêprocuraumavariáveldoescopodeaplicação,usamosavariávelimplícitachamadaapplicationScope:

Acessandoescopoapplication:${applicationScope['nomeGlobal']}<br/>

17.9OSERVLETCONTEXTEOESCOPODEAPLICAÇÃO 245

Page 255: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

MÉTODOSNOSERVLETCONTEXT

AlémdacaracterísticadeescopoglobalcomosmétodosgetAttributeesetAttribute,

outrosmétodosúteisexistemnaServletContext.ConsulteoJavadocparamaisinformações.

HáaindaoutroslistenersdisponíveisnaAPIdeServletsparacapturaroutrostiposdeeventos:

HttpSessionListener - provê métodos que executam quando uma sessão é criada

(sessionCreated),destruída(sessionDestroyed);

ServletContextAttributeListener - permite descobrir quando atributos sãomanipuladosno

ServletContext com os métodos attributeAdded , attributeRemoved e

attributeReplaced;

ServletRequestAttributeListener - tem os mesmos métodos que o

ServletContextAttributeListener mas executa quando os atributos do request são

manipulados;

HttpSessionAttributeListener - tem os mesmos métodos que o

ServletContextAttributeListener mas executa quando os atributos da HttpSession são

manipulados;

ServletRequestListener - permite executar códigos nosmomentos que um request chega e

quandoeleacabadeserprocessado(métodosrequestDestroyederequestInitialized);

Outrosmenosusados:HttpSessionActivationListenereHttpSessionBindingListener.

Aconfiguraçãodequalquerumdesseslistenerséfeitacomatag<listener>comovimosacima.

É possível inclusive que uma mesma classe implemente várias das interfaces de listeners mas sejaconfiguradaapenasumavezoweb.xml.

17.10OUTROSLISTENERS

246 17.10OUTROSLISTENERS

Page 256: uso comercial deste material, por favor, consulte a Caelum ... · 13 Spring IoC e deploy da aplicação 13.1 Menos acoplamento com inversão de controle e injeção de dependências

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoJavaparaDesenvolvimentoWeb

VocêpodetambémfazerocursodatadessaapostilanaCaelum

17.10OUTROSLISTENERS 247