How Spring Web MVC Really Works

Introduction

This is an in-depth look at the powerful features and internal working of Spring Web MVC, which is a part of the Spring Framework.

o código fonte para este artigo está disponível no GitHub.

configuração do projecto

ao longo deste artigo, utilizaremos o mais recente e maior Framework de primavera 5., Estamos focando aqui a clássica pilha web da primavera, que tem sido disponível a partir das primeiras versões do framework e ainda é a principal forma de construir aplicações web com a Primavera.

para começar, para configurar o seu projecto de teste, irá usar o arranque de primavera e algumas das suas dependências iniciais; também terá de definir o pai:

lembre-se que, para usar a primavera 5, terá de usar também o arranque de Primavera 2.X. No momento da escrita, este é um lançamento de Marco, disponível no repositório de Marco Da Primavera., Vamos adicionar este repositório ao seu projecto Maven:

poderá verificar a versão actual do arranque de primavera no Maven Central.

Sample Project

para compreender como funciona o MVC Web da primavera, irá implementar uma aplicação simples com uma página de login. Para mostrar a página de autenticação, crie um @Controller-anotado classe InternalController com um mapeamento GET para a raiz de contexto.

O método hello() não tem parâmetros. Ele retorna uma String que é interpretada pelo MVC Spring como um nome de vista (no nosso caso, o login.,html template):

import org.springframework.web.bind.annotation.GetMapping;@GetMapping("/")public String hello() { return "login";}

para processar um login do usuário, crie outro método que lida com pedidos POST com dados de login. Ele então redireciona o Usuário para a página de sucesso ou falha, dependendo do resultado.,

Note que o início de sessão() método recebe um objeto de domínio como um argumento e retorna um ModelAndView objeto:

ModelAndView é titular de dois objetos distintos:

  • Modelo – um valor-chave mapa de dados utilizado para renderizar a página
  • modo de Exibição – um modelo de página, que é preenchida com os dados do modelo

Estas são unidas por conveniência de modo a que o controlador método pode retornar os dois ao mesmo tempo.

para desenhar a sua página HTML, use o Thymeleaf como um motor de modelo de visualização, que tem uma integração sólida e fora da caixa com a mola.,

Servlets as the Foundation of a Java Web Application

So, what does actually happen when you type http://localhost:8080/ in the browser, press Enter, and the request hits the web server? Como você começa a partir deste pedido para ver um formulário web no navegador?

dado que o projecto é uma aplicação de arranque de molas simples, poderá executá-lo através da aplicação Spring5.

Spring Boot usa o Apache Tomcat por padrão., Assim, executando a aplicação, é provável que você veja a seguinte informação no log:

Uma vez que Tomcat é um container Servlet, naturalmente cada pedido HTTP enviado para um servidor web Tomcat é processado por um servlet Java. Então o ponto de entrada da aplicação Spring Web é, não surpreendentemente, um servlet.

um servlet é, simplesmente, um componente principal de qualquer aplicação web Java; é de baixo nível e não impõe muito no caminho de padrões de programação específicos, como o MVC.

um servlet HTTP só pode receber um pedido HTTP, processá-lo de alguma forma, e enviar uma resposta de volta.,

e, a partir da API Servlet 3.0, poderá agora ultrapassar a configuração XML e começar a alavancar a configuração Java (com restrições menores).,

DispatcherServlet como o Coração de Spring MVC

o Que nós realmente queremos fazer como os desenvolvedores de aplicativo da web é abstraem os seguintes chato e clichê tarefas e o foco na úteis lógica de negócios:

  • mapeamento de uma solicitação HTTP para um determinado método de processamento
  • análise dos dados de solicitação HTTP e cabeçalhos em objetos de transferência de dados (DTOs) de domínio ou de objetos
  • modelo-vista-controlador de interação
  • geração de respostas de DTOs, objetos de domínio, etc.

o Spring DispatcherServlet fornece exatamente isso., É o coração do framework MVC Web da primavera; este componente central recebe todos os pedidos para a sua aplicação.como verá, o DispatcherServlet é muito extensível.,chapeamento de motores, XML, XSLT ou qualquer outro modo de exibição tecnologia (implementações de ViewResolver interface)

  • analisar multipart pedidos utilizando o padrão do Apache Commons para carregar ficheiros de implementação ou escrever o seu próprio MultipartResolver
  • resolver localidade com qualquer LocaleResolver implementação, incluindo o cookie de sessão, Aceitar cabeçalho HTTP, ou qualquer outra forma de determinar a localidade esperado pelo usuário
  • o Processamento de uma Solicitação HTTP

    Primeiro, vamos traçar o processamento de simples pedidos de HTTP a um método em sua camada controller (controlador) e de volta ao browser do cliente.,

    O DispatcherServlet tem uma longa hierarquia de herança; vale a pena compreender estes aspectos individuais um a um, de cima para baixo. Os métodos de processamento de pedidos vão nos interessar mais.

    compreender a solicitação HTTP, tanto localmente durante o desenvolvimento padrão, como remotamente, é uma parte crítica da compreensão da arquitetura MVC.

    GenericServlet

    GenericServlet é uma parte da especificação Servlet não focada diretamente em HTTP. Define o método de serviço() que recebe pedidos recebidos e produz respostas.,

    Observe como ServletRequest e ServletResponse método argumentos não estão vinculados ao protocolo HTTP:

    public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    Este é o método que, eventualmente, é chamado em qualquer solicitação para o servidor, incluindo um pedido GET simples.

    HttpServlet

    HttpServlet class is, as the name suggests, the HTTP-focused Servlet implementation, also defined by the specification.,

    em termos mais práticos, HttpServlet é uma classe abstrata com uma implementação de método service() que divide os pedidos pelo tipo de método HTTP e se parece mais ou menos com isto:

    HttpServletBean

    Next, HttpServletBean é a primeira classe de Spring-aware na hierarquia. Ele injeta as propriedades do bean usando os valores servlet init-param recebidos da web.xml ou do Inicializador de Aplicações Web.

    no caso das solicitações para a sua aplicação, os métodos doGet(), doPost(), etc são chamados para essas solicitações HTTP específicas.,

    FrameworkServlet

    FrameworkServlet integra a funcionalidade Servlet com um contexto de aplicação web, implementando a interface ApplicationContextAware. Mas também é capaz de criar um contexto de aplicação web por conta própria.

    Como já viu, a superclasse HttpServletBean injecta init-params como propriedades do bean. Então, se um nome de classe de contexto é fornecido no contextClass init-param do servlet, então uma instância desta classe será criada como um contexto de Aplicação. Caso contrário, será usada uma classe xmlwebapplicationcontext.,

    Como a configuração do XML está fora de estilo hoje em dia, o Spring Boot configura o DispatcherServlet com o AnnotationConfigWebApplicationContext por omissão. Mas podes mudar assim tão facilmente.

    por exemplo, se precisar de configurar a sua aplicação MVC Web de primavera com um contexto de aplicação baseado em Groovy, poderá usar a seguinte configuração do DispatcherServlet na web.xml file:

     dispatcherServlet org.springframework.web.servlet.DispatcherServlet contextClass org.springframework.web.context.support.GroovyWebApplicationContext 

    a mesma configuração pode ser feita de uma forma mais moderna baseada em Java usando a classe WebApplication initializer.,

    DispatcherServlet: Unifying the Request Processing

    The HttpServlet.a implementação de serviço (), que encaminha pedidos pelo tipo de verbo HTTP, faz todo o sentido no contexto de servlets de baixo nível. No entanto, no nível MVC de primavera de abstração, o tipo de método é apenas um dos parâmetros que podem ser usados para mapear o pedido para o seu manipulador.,

    assim, o outro principal função do FrameworkServlet classe é juntar-se a lógica de manipulação de volta em um único método processRequest (), que por sua vez chama o doService() método:

    @Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}@Overrideprotected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response);}// …

    DispatcherServlet: Enriquecendo o Pedido

    Finalmente, o DispatcherServlet implementa o doService() método. Aqui, ele adiciona ao pedido alguns objetos úteis que podem vir a ser úteis para baixo o pipeline de processamento: contexto de aplicação web, resolução local, resolução de temas, fonte de tema etc.:

    também, o método doService() prepara mapas flash de entrada e saída., Flash map é basicamente um padrão para passar parâmetros de um pedido para outro pedido que se segue imediatamente. Isto pode ser muito útil durante os redirecionamentos (como mostrar ao usuário uma mensagem de informação de um tiro após o redirecionamento):

    então, o método doService () chama o método doDispatch () que é responsável pela requisição de envio.

    DispatcherServlet: envio do pedido

    o principal objectivo do método de expedição() é encontrar um manipulador adequado para o pedido e dar-lhe os parâmetros de pedido/resposta., O manipulador é basicamente qualquer tipo de objeto e não se limita a uma interface específica. Isso também significa que Spring precisa encontrar um adaptador para este manipulador que sabe como “falar” com o manipulador.

    para encontrar o manipulador que corresponde ao pedido, a mola passa pelas implementações registadas da interface de mapeamento de mãos. Existem muitas implementações diferentes que podem atender às suas necessidades.

    SimpleUrlHandlerMapping permite mapear um pedido por sua URL para um determinado feijão de processamento. Por exemplo, ele pode ser configurado injetando sua propriedade mappings com um java.util.,Instância de propriedades semelhante a esta:

    /welcome.html=ticketController/show.html=ticketController

    provavelmente a classe mais usada para mapeamento de manipuladores é RequestMappingHandlerMapping, que mapeia um pedido para um método @RequestMapping-anotado de uma classe de controlador@. Este é exatamente o mapeamento que conecta o dispatcher com os métodos hello() e login() do seu controlador.

    Note que os seus métodos de primavera estão anotados com @GetMapping e @PostMapping de forma correspondente. Estas anotações, por sua vez, são marcadas com a meta-anotação @RequestMapping.,

    dispatch() método cuida também de alguns outros HTTP tarefas específicas:

    • curto-circuito de processamento da solicitação GET no caso, o recurso não foi modificado
    • aplicar a multipart de resolução de correspondentes pedidos
    • curto-circuito de processamento do pedido, se o manipulador escolheu para lidar com isso de forma assíncrona

    Tratamento do Pedido

    Agora que a Primavera determinado o processador para o pedido e o adaptador para o manipulador, é hora de finalmente processar o pedido. Aqui está a assinatura do HandlerAdapter.handle () method., É importante notar que o processador tem uma escolha de como lidar com o pedido:

    • gravar os dados para o objeto de resposta por si mesma e retornar null

    retornar um ModelAndView objeto a ser processado pelo DispatcherServlet

    @NullableModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    Existem vários fornecido tipos de manipuladores. Aqui está como o SimpleControllerHandlerAdapter processa uma instância de controlador MVC de primavera (não o confunda com um POJO anotado pelo @Controller-anotado).,

    Notice how the controller handler returns ModelAndView object and does not render the view by itself:

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response);}

    the second is SimpleServletHandlerAdapter, which adapts a regular Servlet as a request handler.

    um Servlet não sabe nada sobre ModelAndView e simplesmente lida com o pedido por si só, tornando o resultado no objeto de resposta., Então este adaptador simplesmente devolve null em vez de ModelAndView:

    no seu caso, um controlador é um POJO com várias anotações @RequestMapping, de modo que qualquer manipulador é basicamente um método desta classe embrulhado numa instância HandlerMethod. Para se adaptar a este tipo de tratador, Spring usa a classe RequestMapping Andleradapter.,

    Processamento de Argumentos e Valores de Retorno de Métodos de Manipulador

    Note que o controlador de métodos não costumam levar HttpServletRequest e HttpServletResponse argumentos, mas em vez disso recebem e devolvem muitos tipos diferentes de dados, tais como objetos de domínio, caminho de parâmetros etc.

    também, note que você não é obrigado a retornar uma instância ModelAndView a partir de um método de controller. Você pode devolver um nome de vista, ou uma ResponseEntity ou um POJO que será convertido a uma resposta JSON etc.,

    O RequestMappingHandlerAdapter garante que os argumentos do método são resolvidos a partir do pedido HttpServlet. Além disso, ele cria o objeto ModelAndView a partir do valor de retorno do método.

    Há um importante pedaço de código no RequestMappingHandlerAdapter que torna-se de tudo isso conversão de magia acontece:

    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers( this.argumentResolvers);}if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers( this.returnValueHandlers);}

    O argumentResolvers objeto é composto de diferentes HandlerMethodArgumentResolver instâncias.

    Existem mais de 30 implementações diferentes de resolução de argumentos., Permitem extrair qualquer tipo de Informação do pedido e fornecê-la como argumentos de método. Isto inclui variáveis do caminho URL, parâmetros do corpo do pedido, cabeçalhos do pedido, cookies, dados de sessão, etc.

    The returnValueHandlers object is a composite of HandlerMethodReturnValueHandler objects. Há também um monte de diferentes manipuladores de valor que podem processar o resultado de seu método para criar objeto ModelAndView esperado pelo adaptador.

    Por exemplo, quando você retorna uma string do método hello (), O ViewNameMethodReturnValueHandler processa o valor., Mas quando você retorna um ModelAndView pronto do método de login (), Spring usa o ModelAndViewMethodReturnValueHandler.

    a visualização

    por esta altura, a primavera já processou o pedido de HTTP e recebeu um objecto ModelAndView, por isso tem de desenhar a página HTML que o Utilizador irá ver no navegador. Ele faz isso com base no modelo e na janela selecionada encapsulada no objeto ModelAndView.

    note também que você pode desenhar um objeto JSON, ou XML, ou qualquer outro formato de dados que possa ser transferido através do protocolo HTTP., Vamos falar mais sobre isso na próxima secção de descanso focada aqui.vamos voltar para a Central. O método render () primeiro define o local de resposta usando a instância de resolução local fornecida. Vamos assumir que o seu navegador moderno define o cabeçalho Accept corretamente e que o Aceiteaderlocaleresolver é usado por padrão.

    durante a renderização, o objecto ModelAndView já poderia conter uma referência a uma vista seleccionada, ou apenas um nome de vista, ou nada se o controlador dependesse de uma vista predefinida.,

    Uma vez que tanto os métodos hello() e login() especificam a vista desejada como um nome de texto, ela tem que ser pesquisada por este nome. Assim, é aqui que entra em jogo a lista de resolvedores de visualizações:

    Esta é uma lista de instâncias de resolução de visualizações, incluindo a nossa visão do futuro fornecida pela biblioteca de integração thymeleaf-spring5. Este resolvedor sabe onde procurar as vistas, e fornece as instâncias de visualização correspondentes.,

    Depois de chamar o método de renderização da view (), a primavera finalmente completa o processamento de Pedidos, enviando a página HTML para o navegador do Usuário:

    suporte de repouso

    além do cenário MVC típico, também podemos usar o framework para criar serviços web REST.

    simplesmente, você pode aceitar um recurso como uma entrada, especificar um POJO como um argumento de método, e anotá-lo com @RequestBody., Você também pode anotar o método em si com o @ ResponseBody para especificar que seu resultado tem que ser transformado diretamente para uma resposta HTTP:

    isto também é possível graças à extensibilidade do MVC de Primavera.

    para marshall os DTOs internos a uma representação de repouso, o framework faz uso da infra-estrutura HttpMessageConverter. Por exemplo, uma das implementações é MappingJackson2HttpMessageConverter, que é capaz de converter objetos modelo para e de JSON usando a Biblioteca Jackson.,

    E para simplificar ainda mais a criação de uma API de descanso, a Primavera introduz a anotação @RestController. Isto é útil para assumir a semântica do @ ResponseBody por padrão e evitar definir explicitamente que em cada controlador de repouso:

    conclusão

    neste artigo, você passou pelo processamento de um pedido no framework MVC da primavera em detalhe. Você viu como diferentes extensões do framework trabalham em conjunto para fornecer toda a magia e poupar-lhe a necessidade de lidar com as partes difíceis do protocolo HTTP.,

    melhore continuamente as suas aplicações Java usando Stackify Retrace, a ferramenta de gerenciamento de desempenho de aplicações de ciclo de vida completo. Experimenta.

    Author: admin

    Deixe uma resposta

    O seu endereço de email não será publicado. Campos obrigatórios marcados com *