segunda-feira, 3 de dezembro de 2012

Spring MVC 3 - parte 4 - Mapeando Requisições

Usa-se @RequestMapping para mapear URLs para uma classe ou um método tratador particular. O seguinte exemplo apresenta a aplicação Petcare, que é uma das aplicações de exemplo da Spring:
   @Controller
   @RequestMapping("/appointments")
   public class AppointmentsController {

      private final AppointmentBook appointmentBook;

      @Autowired
      public AppointmentsController(AppointmentBook appointmentBook) {
         this.appointmentBook = appointmentBook;
      }

      @RequestMapping(method = RequestMethod.GET)
      public Map<String, Appointment> get() {
         return appointmentBook.getAppointmentsForToday();
      }

      @RequestMapping(value="/{day}", method = RequestMethod.GET)
      public Map<String, Appointment> getForDay(
         @PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, 
         Model model {
          return appointmentBook.getAppointmentsForDay(day);
      }

      @RequestMapping(value="/new", method = RequestMethod.GET)
      public AppointmentForm getNewForm() {
         return new AppointmentForm();
      }

      @RequestMapping(method = RequestMethod.POST)
      public String add(@Valid AppointmentForm appointment, 
         BindingResult result) {
         if (result.hasErrors()) {
            return "appointments/new";
         }

         appointmentBook.addAppointment(appointment);
         return "redirect:/appointments";
      }
   }  
Neste exemplo, @RequestMapping é usada em vários lugares. Primeiro, é usada em nível de classe, indicando que todos os métodos tratadores neste controle são relativos ao path /appointments. O método get() tem um melhor refinamento: aceita requisições do tipo GET, quer dizer, qualquer HTTP GET para /appointments invocará este método. O método add() é similar: aceita requisições do tipo POST, quer dizer, qualquer HTTP POST para /appointments invocará este método. O método getNewForm() combina a definição de método HTTP e path, então, qualquer requisição do tipo GET para appointments/new será tratada por esse método. O método getForDay() apresenta outro uso para @RequestMapping e será detalhado posteriormente.

quarta-feira, 14 de novembro de 2012

Spring MVC 3 - Índice

Estou escrevendo uma série de artigos sobre o framework Web Spring MVC 3. 
Estarei disponbilizando esses artigos conforme for escrevendo.
Até a parte 3 já está disponível no blog.
Espero que seja útil para a comunidade de desenvolvedores. 

  • Parte 1 - Introdução - clique aqui para leitura
  • Parte 2 - Configuração - clique aqui para leitura
  • Parte 3 - Controladores - clique aqui para leitura
  • Parte 4 - Mapeando Requisições - clique aqui para leitura
  • Parte 5 - Views
  • Parte 6 - Interceptando Requisições
  • Parte 7 - Internacionalizando a Aplicação
  • Parte 8 - View Resolver
  • Parte 9 - Exceções
  • Parte 10 - Tratando Formulários
  • Parte 11 - Bean Validation
  • Spring MVC 3 - Parte 3 - Controladores

    Uma classe de Controle do Spring MVC possui métodos tratadores para requisições de usuário. Utiliza a anotação de classe @Controller e possui a anotação @RequestMapping que pode ser aplicada em nível de classe ou método. Em nível de classe mapeia uma URL para a classe de controle e, então, um método particular HTTP mapeia para cada método do controle. Controle interpreta a entrada do usuário e a transorma dentro de um modelo que é apresentado ao usuário através de uma view.
        package ... ;
    
        ...
        import org.springframework.stereotype.Controller;
        import org.springframework.web.bind.annotation.RequestMapping;
        import org.springframework.web.bind.annotation.RequestMethod;
        import org.springframework.web.servlet.ModelAndView;
        import org.springframework.ui.Model;
    
        @Controller
        @RequestMapping("/welcome")
        public class WelcomeController {
        
            @RequestMapping(method = RequestMethod.GET)
            public String welcome(Model model) {
                Date today = new Date();
                model.addAttribute("today", today);
                return "welcome";
           }
        }
    
    
    O exemplo acima é um controle do Spring MVC, mapeado com a anotação @Controller. O primeiro @RequestMapping é usado em nível de classe para especificar que qualquer requisição recebida para /welcome será atendida por este controle. O segundo @RequestMapping é usado em nível de método e, nesse caso, atende qualquer requisição HTTP GET. No caso, este método é o método default para este controle e toda requisição recebida para /welcome será direcionada para o método welcome(Model model). No caso deste controle, se nenhum método HTTP GET default fosse declarado, a exceção ServletException seria lançada. Uma variação deste comportamento seria declarar ambos os valores no método:
        @Controller
        public class WelcomeController {
    
            @RequestMapping(value = "/welcome", method=RequestMethod.GET)
            public String welcome(Model model) {
            ...
    
    
    Um outro exemplo de método tratador no controle pode ser visto abaixo. Ele recebe todas as requisições HTTP POST enviadas para o controle, normalmente enviadas pelo usuário após submeter um HTML form, além de dois parâmetros de entrada. O primeiro é @RequestParam("courtName") String courtName, usado para extrair o parâmetro de requisição chamado courtName. O segundo parâmetro é Model model, usado para definir um objeto que podemos passar dados e retornar para a view. Na execução do método, uma variável chamada reservations é adicionada ao objeto Model, tornando-se disponível para retornar a visão para ser apresentada ao usuário e o método finaliza com um retorno para a view reservationQuery, indicada pela string de retorno.
        
        @RequestMapping(method = RequestMethod.POST)
        public String sumbitForm(@RequestParam("courtName") String courtName, Model model) {
            List reservations = java.util.Collections.emptyList();
            if (courtName != null) {
                reservations = reservationService.query(courtName);
           }
           model.addAttribute("reservations", reservations);
           return "reservationQuery";
        }
    
    
    Para habilitar auto detecção das classes de controle anotadas na sua aplicação, é necessário configurar o contexto do Spring informando o pacote base das classes de controle, conforme pode ser visto ne exemplo abaixo:
     
       <?xml version="1.0" encoding="UTF-8"?>
       <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:p="http://www.springframework.org/schema/p"
            xmlns:context="http://www.springframework.org/schema/context"
            xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
            <context:component-scan base-package=
                  "org.springframework.samples.petclinic.web"/>
    
            <!-- ... -->
       </beans>
    

    Spring MVC 3 - Parte 2 - Configurações

    Usando Maven, é preciso informar as dependências abaixo para desenvolver uma aplicação com Spring MVC:
        
            org.springframework
            spring-webmvc
            ${spring.version}
        
        
            org.springframework
            spring-web
            ${spring.version}
        
    
    É necessário configurar o servlet do Spring MVC no arquivo web.xml:
        
            ...
       
            
                aplicacao
                
                    org.springframework.web.servlet.DispatcherServlet
                
                1
            
            
                aplicacao
                /
            
        
    
    É necessário criar um arquivo xml do Spring para carregar as configurações para o Spring MVC. Por default, esse arquivo terá o nome do servlet, informando no arquivo web.xml, acrescido de -servlet.xml. Usando como exemplo a configuração do web.xml acima, o nome do arquivo seria aplicacao-servlet.xml. É possível especificar um outro nome utilizando o parâmetro contextConfigLocation no arquivo web.xml. Para carregar outros arquivos de configuração do Spring, ao lado do arquivo do Spring MVC, neste caso aplicacao-servlet.xml, é necessário definir o listener ContextLoaderListener no web.xml. Por default, ele carrega o arquivo /WEB-INF/applicationContext.xml, mas pode-se especificar outros arquivos, usando o parâmetro contextConfigLocation. Os arquivos de configuração devem ser separados por vírgula ou espaços.
        
            ...
    
            
                contextConfigLocation
                /WEB-INF/aplicacao-service.xml
            
            
                
                    org.springframework.web.context.ContextLoaderListener
                
            
        
    
    É necessário configurar a aplicação para escanear a presença de anotações nas classes de controle do Spring MVC, como @Controller e @RequestMapping. Para isso, é preciso habilitar o Spring para detectar as anotações através do elemento informando o pacote base da aplicação, que será a raiz para procurar pelas anotações. Em adição, a anotação @RequestMapping mapeia requisições URLs para classes controladoras e respectivos métodos. Por isso, é preciso registrar também as classes DefaultAnnotationHandlerMapping e AnnotationMethodHandlerAdapter. A primeira, para processar requisições em nível de classe e a segunda, em nível de método. A seguir, encontra-se um exemplo dessas configurações, que podem ser incluídas no arquivo de configuração do Spring MVC.
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/
                                               spring-context-3.0.xsd">
    
           <context:component-scan
                base-package="com.apress.springrecipes.court.web" />
            
           <bean class="org.springframework.web.servlet.mvc.annotation.
                                   DefaultAnnotationHandlerMapping" />
    
           <bean class="org.springframework.web.servlet.mvc.annotation.
                                    AnnotationMethodHandlerAdapter" />
    </beans>