Mvc model view controller - java para desenvolvimento web

  • Published on
    29-Jun-2015

  • View
    289

  • Download
    3

Embed Size (px)

DESCRIPTION

Apostila da Caelum. Disponibilizada online pela prpria Caelum.

Transcript

<ul><li> 1. 25/4/2014 MVC - Model View Controller - Java para Desenvolvimento Web http://www.caelum.com.br/apostila-java-web/mvc-model-view-controller/ 1/14 CAPTULO 9 MVC - Model View Controller "Ensinar aprender duas vezes." Joseph Joubert Nesse captulo, voc aprender: O padro arquitetural MVC; A construir um framework MVC simples. 9.1 - SERVLET OU JSP? Colocar todo HTML dentro de uma Servlet realmente no nos parece a melhor ideia. O que acontece quando precisamos mudar o design da pgina? O designer no vai saber Java para editar a Servlet, recompil-la e coloc-la no servidor. Imagine usar apenas JSP. Ficaramos com muito scriptlet, que muito difcil de dar manuteno. Uma ideia mais interessante usar o que bom de cada um dos dois. O JSP foi feito apenas para apresentar o resultado, e ele no deveria fazer acessos a banco de dados e nem fazer a instanciao de objetos. Isso deveria estar em cdigo Java, na Servlet. O ideal ento que a Servlet faa o trabalho rduo, a tal da lgica de negcio. E o JSP apenas apresente visualmente os resultados gerados pela Servlet. A Servlet ficaria ento com a lgica de negcios (ou regras de negcio) e o JSP tem a lgica de apresentao. Imagine o cdigo do mtodo da servlet AdicionaContatoServletque fizemos antes: protectedvoidservice(HttpServletRequestrequest, HttpServletResponseresponse){ //log System.out.println("Tentandocriarumnovocontato..."); //acessaobean Contatocontato=newContato(); //chamaossetters ... //adicionaaobancodedados ContatoDaodao=newContatoDao(); dao.adiciona(contato); //ok....visualizao out.println(""); out.println(""); out.println("Contato"+contato.getNome()+ "adicionadocomsucesso"); out.println(""); APOSTILA JAVA PARA DESENVOLVIMENTO WEB </li></ul><p> 2. 25/4/2014 MVC - Model View Controller - Java para Desenvolvimento Web http://www.caelum.com.br/apostila-java-web/mvc-model-view-controller/ 2/14 Repare que, no final do nosso mtodo, misturamos o cdigo HTML com Java. O que queremos extrair do cdigo acima justamente essas ltimas linhas. Seria muito mais interessante para o programador e para o designer ter um arquivo JSP chamado contato-adicionado.jspapenas com o HTML: Buscamos uma forma de redirecionar as requisies, capaz de encaminhar essa requisio para um outro recurso do servidor: por exemplo indo de uma servlet para um JSP. Para isso, fazemos o dispatch das requisies, para que o JSP s seja renderizado depois que suas regras de negcio, dentro de uma servlet por exemplo, foram executadas. 9.2 - REQUEST DISPATCHER Poderamos melhorar a nossa aplicao se trabalhssemos com o cdigo Java na servlet e o HTML apenas no JSP. A API de Servletsnos permite fazer tal redirecionamento. Basta conhecermos a URL que queremos acessar e podemos usar um objeto RequestDispatcherpara acessar outro recurso Web, seja esse recurso uma pgina JSP ou uma servlet: Podemos facilmente executar a lgica de nossa aplicao Web em uma servlet e ento redirecionar para uma pgina JSP, onde voc possui seu cdigo HTML e tags que iro manipular os dados trazidos pela servlet. Forward e include O mtodo forwards pode ser chamado quando nada foi ainda escrito para a sada. No momento que algo for escrito, fica impossvel redirecionar o usurio, pois o protocolo HTTP no possui meios de voltar atrs naquilo que j foi enviado ao cliente. Existe outro mtodo da classe RequestDispatcherque representa a incluso de pgina e no o redirecionamento. Esse mtodo se chama includee pode ser chamado a qualquer instante para acrescentar ao resultado de uma pgina os dados de outra. out.println(""); } Contato${param.nome}adicionadocomsucesso RequestDispatcherrd=request .getRequestDispatcher("/contato-adicionado.jsp"); rd.forward(request,response); 3. 25/4/2014 MVC - Model View Controller - Java para Desenvolvimento Web http://www.caelum.com.br/apostila-java-web/mvc-model-view-controller/ 3/14 Voc pode tambm fazer o curso FJ-21 dessa apostila na Caelum Querendo aprender ainda mais sobre Java na Web e Hibernate? Esclarecer dvidas dos exerccios? Ouvir explicaes detalhadas com um instrutor? A Caelum oferece o curso FJ-21 presencial nas cidades de So Paulo, Rio de Janeiro e Braslia, alm de turmas incompany. Consulte as vantagens do curso Java para Desenvolvimento Web. 9.3 - EXERCCIOS: REQUESTDISPATCHER Vamos evoluir nossa adio de contatos antes puramente usando Servlets para usar o RequestDispatcher. 1. Seguindo a separao aprendida nesse captulo, queremos deixar em um JSP separado a responsabilidade de montar o HTML a ser devolvido para o usurio. Crie ento um novo arquivo contato-adicionado.jsp na pasta WebContent: 2. Altere sua servlet AdicionaContatoServletpara que, aps a execuo da lgica de negcios, o fluxo da requisio seja redirecionado para nosso novo JSP. Remova no fim da classe o cdigo que monta a sada HTML (as chamadas de out.println). Vamos substituir por uma chamada ao RequestDispatchere exibir o mesmo resultado usando o JSP que criamos. A chamada fica no final de nossa servlet: 3. Teste a URL: http://localhost:8080/fj21-agenda/adiciona-contato.jsp Resultado Contato${param.nome}adicionadocomsucesso RequestDispatcherrd=request .getRequestDispatcher("/contato-adicionado.jsp"); rd.forward(request,response); 4. 25/4/2014 MVC - Model View Controller - Java para Desenvolvimento Web http://www.caelum.com.br/apostila-java-web/mvc-model-view-controller/ 4/14 Perceba que j atingimos um resultado que no era possvel anteriormente. Muitos projetos antigos que foram escritos em Java utilizavam somente JSP ou servlets e o resultado era assustador: diferentes linguagens misturadas num nico arquivo, tornando difcil a tarefa de manuteno do cdigo. Com o contedo mostrado at esse momento, possvel escrever um cdigo com muito mais qualidade: cada tecnologia com a sua responsabilidade. 9.4 - MELHORANDO O PROCESSO Aqui temos vrias servlets acessando o banco de dados, trabalhando com os DAOs e pedindo para que o JSP apresente esses dados, o diagrama a seguir mostra a representao do AdicionaContatoServletaps a modificao do exerccio anterior. Temos o problema de ter muitas servlets. Para cada lgica de negcios, teramos uma servlet diferente, que significa vrias portas de entradas, algo abominvel em um projeto de verdade. Imagine dez classes de modelo, cinco lgicas diferentes, isso totaliza cinquenta formas diferentes de acesso. E se quisssemos fazer um Log das chamadas dessas lgicas? Teramos que espalhar o cdigo para esse Log por toda nossa aplicao. Sabemos da existncia de ferramentas para gerar tal cdigo automaticamente, mas isso no resolve o problema da complexidade de administrar tantas servlets. Utilizaremos uma ideia que diminuir bastante o nmero de portas de entradas em nossa aplicao: colocar tudo em uma Servlet s e, de acordo com os parmetros que o cliente usar, decidimos o que executar. Teramos a uma Servlet para controlar essa parte, como o esboo abaixo: //TodasaslgicasdentrodeumaServlet @WebServlet("/sistema") publicclassSistemaTodoServletextendsHttpServlet{ protectedvoidservice(HttpServletRequestrequest, HttpServletResponseresponse){ Stringacao=request.getParameter("logica"); 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")){ //fazaremooeredirecionaparaalista } } } 5. 25/4/2014 MVC - Model View Controller - Java para Desenvolvimento Web http://www.caelum.com.br/apostila-java-web/mvc-model-view-controller/ 5/14 Poderamos acessar no navegador algo como http://localhost:8080//sistema?logica=AdicionaContato. Mas para cada ao teramos um if/ else if, tornando a Servlet muito grande, com toda regra de negcio do sistema inteiro. Podemos melhorar fazendo refactoring de extrair mtodos. Mas continuaramos com uma classe muito grande. Seria melhor colocar cada regra de negcio (como inserir contato, remover contato, fazer relatrio etc) em uma classe separada. Cada ao (regra de negcio) em nossa aplicao estaria em uma classe. Ento vamos extrair a nossa lgica para diferentes classes, para que nossa Servlet pudesse ter um cdigo mais enxuto como esse: E teramos classes AdicionaContato, ListaContatos, etc com um mtodo (digamos, executa) que faz a lgica de negcios apropriada. Porm, a cada lgica nova, lgica removida, alterao etc, temos que alterar essa servlet. Isso trabalhoso e muito propenso a erros. Repare dois pontos no cdigo acima. Primeiro que ele possui o mesmo comportamento de switch! E switchem Java quase sempre pode ser substitudo com vantagem por polimorfismo, como veremos a seguir. Outra questo que recebemos como parmetro justamente o nome da classe que chamamos em seguida. Vamos tentar generalizar ento, queremos executar o seguinte cdigo: Queremos pegar o nome da classe a partir do parmetro e instanci-la. Entretanto no podemos, pois nomeDaClasse o nome de uma varivel e o cdigo acima no vlido. O nosso problema que s sabemos o que vamos instanciar em tempo de execuo (quando o parmetro chegar) e no em tempo de compilao. Mas a partir do nome da classe ns podemos recuperar um objeto que representar as informaes contidas dentro daquela classe, como por exemplo atributos, mtodos e construtores. Para que consigamos esse objeto, basta utilizarmos a classe Classinvocando o mtodo forNameindicando de qual classe queremos uma representao. Isso nos retornar um objeto do tipo Class representando a classe. Como abaixo: timo, podemos ter uma representao de AdicionaContatoou de ListaContatoe assim por diante. Mas precisamos de alguma forma instanciar essas classes. J que uma das informaes guardadas pelo objeto do tipo Class o construtor, ns podemos invoc-lo para instanciar a classe atravs do mtodo newInstance. E como chamar o mtodo executa? Repare que o tipo declarado do nosso objeto Object. Dessa forma, no podemos chamar o mtodo executa. Uma primeira alternativa seramos fazer novamente if/elsepara sabermos qual a lgica que if(acao.equals("AdicionaContato")){ newAdicionaContato().executa(request,response); }elseif(acao.equals("ListaContato")){ newListaContatos().executa(request,response); } StringnomeDaClasse=request.getParameter("logica"); newnomeDaClasse().executa(request,response); StringnomeDaClasse="br.com.caelum.mvc.logica."+ request.getParameter("logica"); Classclasse=Class.forName(nomeDaClasse); Objectobjeto=classe.newInstance(); 6. 25/4/2014 MVC - Model View Controller - Java para Desenvolvimento Web http://www.caelum.com.br/apostila-java-web/mvc-model-view-controller/ 6/14 est sendo invocada, como abaixo: Mas estamos voltando para o if/elseque estvamos fugindo no comeo. Isso no bom. Todo esse if/else ocasionado por conta do tipo de retorno do mtodo newInstanceser Objecte ns tratarmos cada uma de nossas lgicas atravs de um tipo diferente. Repare que, tanto AdicionaContatoquanto ListaContatos, so consideradas Logicas dentro do nosso contexto. O que podemos fazer ento tratar ambas como algo que siga o contrato de Logicaimplementando uma interface de mesmo nome que declare o mtodo executa: Podemos simplificar nossa Servletpara executar a lgica de forma polimrfica e, tudo aquilo que fazamos em aproximadamente 8 linhas de cdigo, podemos fazer em apenas 2: Dessa forma, uma lgica simples para logar algo no console poderia ser equivalente a: Algum precisa controlar ento que ao ser executada para cada requisio, e que JSP ser utilizado. Podemos usar uma servlet para isso, e ento ela passa a ser a servlet controladora da nossa aplicao, chamando a ao correta e fazendo o dispatch para o JSP desejado. Melhorando ainda mais nossa servlet controladora, poderamos deixar nela a responsabilidade de nos redirecionar para uma pgina JSP ou para qualquer outra lgica ao final da execuo das lgicas, bastando que o mtodo executaretorne um simples String, eliminando toda a repetio de cdigo RequestDispatcher. Comearamos alterando a assinatura do mtodo executada interface Logica que era voide agora retornar String: Depois faramos as lgicas retornarem um Stringcom o nome do .jsp que deve ser chamado ao final das suas execues. 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 publicinterfaceLogica{ voidexecuta(HttpServletRequestreq, HttpServletResponseres) throwsException; } Logicalogica=(Logica)classe.newInstance(); logica.executa(request,response); publicclassPrimeiraLogicaimplementsLogica{ publicvoidexecuta(HttpServletRequestreq, HttpServletResponseres) throwsException{ System.out.println("Executandoalogicaeredirecionando..."); RequestDispatcherrd=req .getRequestDispatcher("primeira-logica.jsp"); rd.forward(req,res); } } publicinterfaceLogica{ Stringexecuta(HttpServletRequestreq,HttpServletResponseres) throwsException; } 7. 25/4/2014 MVC - Model View Controller - Java para Desenvolvimento Web http://www.caelum.com.br/apostila-java-web/mvc-model-view-controller/ 7/14 Por fim, a servlet controladora deve receber esse Stringe implementar o cdigo de RequestDispatcher: 9.5 - RETOMANDO O DESIGN PATTERN FACTORY Note que o mtodo forNameda classe Classretorna um objeto do tipo Class, mas esse objeto novo? Foi reciclado atravs de um cache desses objetos? Repare que no sabemos o que acontece exatamente dentro do mtodo forName, mas ao invoc-lo e a execuo ocorrer com sucesso, sabemos que a classe que foi passada em forma de Stringfoi lida e inicializada dentro da virtual machine. Na primeira chamada a Class.forNamepara determinada classe, ela inicializada. J em uma chamada posterior, Class.forNamedevolve a classe que j foi lida e est na memria, tudo isso sem que afete o nosso cdigo. Esse exemplo do Class.forName timo para mostrar que qualquer cdigo que isola a instanciao atravs de algum recurso diferente do construtor uma factory. Tire suas dvidas no novo GUJ Respostas O GUJ um dos principais fruns brasileiros de computao e o maior em portugus sobre Java. A nova verso do GUJ baseada em uma ferramenta de perguntas e respostas (QA) e tem uma comunidade muito forte. So mais de 150 mil usurios pra ajudar voc a esclarecer suas dvidas. Faa sua pergunta. 9.6 - EXERCCIOS: CRIANDO NOSSAS LGICAS E A SERVLET DE CONTROLE publicclassPrimeiraLogicaimplementsLogica{ publicStringexecuta(HttpServletRequestreq, HttpServletResponseres) throwsException{ System.out.println("Executandoalogicaeredirecionando..."); return"primeira-logica.jsp"; } } @WebServlet("/sistema") publicclassControllerServletextendsHttpServlet{ protectedvoidservice(HttpS...</p>