Introdução
Como sabemos, o sucesso do Java veio justamente graças à evolução do software que busca se conectar à rede. Portanto, tomaremos como base o aplicativo de console usual “ Hello World ” e entenderemos o que ele precisa para se tornar um aplicativo de rede a partir de um aplicativo de console. Então, primeiro você precisa criar um projeto Java. Os programadores são pessoas preguiçosas. Nos tempos pré-históricos, quando alguns caçavam mamutes, outros sentavam-se e tentavam não se confundir com toda a variedade de bibliotecas e estruturas de diretórios Java. Para que o desenvolvedor possa controlar o processo de criação de um aplicativo, para que ele possa simplesmente escrever “Quero uma biblioteca de tal e tal versão 2”, eles criaram ferramentas especiais - sistemas de construção. Os dois mais famosos são Maven e Gradle . Para este artigo usaremos Gradle. Se antes teríamos que criar nós mesmos a estrutura de diretórios, agora o Gradle, usando o Gradle Init Plugin, nos permite criar um projeto Java com uma estrutura de diretórios e uma classe Main base em um comando:gradle init --type java-application
Este comando executa a inicialização (init) para nos um aplicativo Java (java-application) com console Hello World. Após a conclusão, um arquivo aparecerá no diretório - build.gradle . Este é o nosso script de construção - ou seja, um script específico para criar um aplicativo com uma descrição de quais ações precisam ser executadas para isso. Vamos abri-lo e adicionar a linha nele: jar.baseName = 'webproject'
Gradle permite realizar diversas ações em um projeto e essas ações são chamadas de tarefas . Ao executar um comando (tarefa) um arquivo JAR será criado gradle build
no diretório /build/libs . E, como você adivinhou, seu nome agora será webproject.jar . Mas se executarmos java -jar ./build/libs/webproject.jar
, obteremos um erro no main manifest attribute
:. Isso ocorre porque para um aplicativo Java você precisa anexar um manifesto - esta é uma descrição de como trabalhar com o aplicativo, como percebê-lo. Então a JVM, que executará a aplicação java, saberá qual classe é o ponto de entrada do programa e outras informações (por exemplo, classpath). Se olharmos mais de perto o conteúdo do script de construção, veremos os plugins sendo conectados. Por exemplo: apply plugin: 'java'
Se formos para a página Gradle Java Plugin , podemos ver que podemos configurar o manifesto:
jar {
manifest {
attributes 'Main-Class': 'App'
}
}
A classe principal, ponto de entrada do programa, foi gerada para nós pelo Gradle Init Plugin. E é ainda especificado no parâmetro mainClassName. Mas isso não nos convinha, porque... esta configuração refere-se a outro plugin, Gradle Application Plugin . Portanto, temos uma aplicação Java que exibe Hello World na tela. Este aplicativo Java é empacotado em um JAR (Java ARchive). É simples, baseado em console e não está atualizado. Como transformá-lo em um aplicativo web?
API de servlet
Para que o Java possa trabalhar com a rede, uma especificação chamada Servlet API apareceu nos tempos antigos . É esta especificação que descreve a interação cliente-servidor, recebendo uma mensagem de um cliente (por exemplo, um navegador) e enviando uma resposta (por exemplo, com o texto de uma página). Naturalmente, muita coisa mudou desde então, mas a questão é que para que uma aplicação Java se torne uma aplicação web, é utilizada a API Servlet. Para não especular infundadamente, vamos pegar essa mesma especificação: JSR-000340 JavaTM Servlet 3.1 . Em primeiro lugar, estamos interessados no “ Capítulo 1: Visão Geral ”. Ele descreve os conceitos básicos que devemos entender. Primeiramente, o que é um servlet? O capítulo " 1.1 O que é um Servlet? " diz que um Servlet é um componente Java que é gerenciado por um container e que gera conteúdo dinâmico. Como outros componentes Java, um servlet é uma classe Java compilada em bytecode e pode ser carregada em um servidor web usando a tecnologia Java. É importante que os servlets interajam com um cliente web (por exemplo, um navegador) dentro da estrutura do paradigma de solicitação/resposta, que é implementado pelo Servlet Container. Acontece que os Servlets residem em algum tipo de contêiner de Servlet. O que é isso? No capítulo " 1.2 O que é um Servlet Container? " é dito que um Servlet Container é alguma parte de um servidor web ou servidor de aplicativos que fornece serviços de rede através dos quais as solicitações são enviadas e as respostas são enviadas. Este mesmo Servlet Container gerencia o ciclo de vida dos servlets. Todos os Servlet Containers são obrigados a suportar, no mínimo, o protocolo HTTP, mas podem suportar outros. Por exemplo, HTTPS. Também é importante que o Servlet Container possa impor quaisquer restrições relacionadas à segurança no ambiente em que os servlets são executados. Também é importante que de acordo com “ 10.6 Web Application Archive File ” a aplicação web seja empacotada em um arquivo WAR (Web ARchive). Ou seja, agora precisamos remover nosso jar e plugins de aplicação para outra coisa. E este é o plugin Gradle WAR . E em vez de jar.baseName especifique war.baseName porque Como não usamos mais o plugin jar, também removemos as configurações do manifesto. Quando lançamos o JAR, a Java Virtual Machine (JVM) precisava ser informada por meio do manifesto sobre como trabalhar com nosso aplicativo. Porque a JVM estava executando isso. A aplicação web, aparentemente, é executada por algum tipo de servidor web. Acontece que ele precisa de alguma forma lhe dizer como trabalhar com nosso aplicativo da web? E acontece que sim. Os aplicativos da Web têm seu próprio manifesto especial. É chamado Descritor de implantação . Uma seção inteira é dedicada a isso: “ 14. Descritor de implantação ”. Há uma seção importante: " Capítulo 10:". Fala sobre o que é uma aplicação web do ponto de vista da API do Servlet. Por exemplo, no capítulo " 10.5 Estrutura de Diretórios " é indicado onde deve estar o Deployment Descriptor:/WEB-INF/web.xml
. Onde colocar o WEB-INF? Conforme declarado no plugin Gradle WAR, ele adiciona um novo layout : src/main/webapp
. Portanto, vamos criar tal diretório, dentro criaremos um diretório WEB-INF, e dentro criaremos um arquivo web.xml. É importante que o diretório é chamado de WEB-INF, e não de META-INF! Vamos copiá-lo de " 14.5.1 Um Exemplo Básico " Exemplo XML:
specification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
Ou seja, precisamos substituir o link para o esquema pelo xsd especificado em todos os lugares, não esquecendo de alterá-lo version="2.5"
para 3.1, e também alterar o namespace em todos os lugares ( xmlns e em xsi:schemaLocation). Eles indicam em qual namespace trabalharemos (para simplificar, quais nomes de elementos podemos usar). Se você abrir o arquivo de esquema, o targetNamespace conterá o mesmo namespace que devemos especificar:
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class App extends HttpServlet {
public String getGreeting() {
return "Hello world.";
}
public void doGet(HttpServletRequest request, HttpServletResponse response) {
response.setContentType("text/html");
try {
response.getWriter().println(getGreeting());
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
}
Mas nosso projeto ainda não está pronto. Porque agora dependemos da API Servlet versão 3.1. Isso significa que em nosso script de construção precisamos indicar uma dependência da API do Servlet. A JVM precisa saber se o que você escreveu no código está correto e como usá-lo. Como lembramos, a especificação consiste essencialmente em interfaces que descrevem como tudo deve funcionar. E as implementações ficam no lado do servidor web. Portanto, sem a API do Servlet haverá um Encontre a biblioteca necessária no Maven Central: javax.servlet-api . E adicione uma entrada ao bloco de dependências . No repositório Maven, como você viu, diz fornecido. Antes de usar uma dependência, você deve especificar o escopo. Gradle não possui um escopo chamado "fornecido", mas possui um escopo " somente compilação ". Portanto, indicaremos: providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
Ugh, parece que está tudo bem? Gradle Build irá construir nosso projeto em um arquivo WAR. E o que devemos fazer a seguir com isso? Primeiro, precisamos de um servidor Web. No Google escrevemos “ lista java de servidores web ” e vemos uma lista de servidores web. Vamos escolher nesta lista, por exemplo, TomCat . Acesse o site do Apache Tomcat , baixe a versão mais recente (atualmente versão 9) como um arquivo zip (se for Windows). Descompacte-o em algum diretório. Viva, temos um servidor web. No diretório do servidor web no subdiretório bin , executamos catalina na linha de comando e vemos as opções disponíveis. Vamos fazer: catalina start
. Cada servidor web possui um diretório que o servidor web monitora. Se um arquivo de aplicativo da web aparecer lá, o servidor da web começará a instalá-lo. Esta instalação é chamada de implantação ou implantação . Sim, sim, é por isso que " descritor de implantação ". Ou seja, como implantar o aplicativo corretamente. No Tomcat, esse diretório é webapps . Vamos copiar a guerra que fizemos usando o gradle build aí. Após isso, no log veremos algo como: Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [время] ms
Para entender melhor ainda, no diretório tomcat editaremos o arquivo \conf\tomcat-users.xml
, adicionando as seguintes linhas:
http://127.0.0.1:8080/manager
aqui veremos os caminhos de todas as aplicações. Nosso webproject provavelmente recebeu o caminho /webproject. Qual é esse caminho? A especificação no capítulo " 10.1 Aplicações Web em Servidores Web " afirma que uma aplicação Web está associada a algum caminho dentro da aplicação (neste caso, /webproject). Todas as solicitações por esse caminho serão associadas ao mesmo ServletContext. Esse caminho também é chamado contextRoot . E de acordo com " 10.2 Relacionamento com ServletContext ", o contêiner de servlet relaciona a aplicação web e o ServletContext um a um. Ou seja, cada aplicação web possui seu próprio ServletContext. O que é um ServletContext ? Como afirma a especificação, um ServletContext é um objeto que fornece aos servlets uma “visão do aplicativo ” no qual estão sendo executados. O Contexto do Servlet é descrito com mais detalhes no Capítulo 4 da especificação da API do Servlet. Surpreendentemente, a API Servlet na versão 3.1 não requer mais a presença de web.xml. Por exemplo, você pode definir um servlet usando anotações:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/app2")
public class App2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
response.getWriter().println("app2");
}
}
Também recomendado no tópico: " Java EE Interview - JEE Servlet API (Perguntas e Respostas) ". Então, temos um Servlet - ele é responsável por qual resposta dar ao cliente web. Temos um ServletContainer que recebe solicitações do usuário, compara o caminho que foi acessado com o caminho do servlet e, se for encontrada uma correspondência, executa o Servlet. Multar. Que lugar ocupa a Primavera nesta imagem do mundo ?
Primavera Web MVC
Ótimo, temos um aplicativo da web. Agora precisamos conectar o Spring. Como podemos fazer isso? Primeiro, você precisa descobrir como conectar corretamente o Spring ao seu projeto. Acontece que antes era possível fazer isso de acordo com a documentação do projeto da plataforma Spring , mas agora “ A plataforma chegará ao fim de sua vida suportada em 9 de abril de 2019 ”, ou seja, não é aconselhável use-o, porque em breve não será mais suportado. A única saída é " Os usuários da plataforma são incentivados a começar a usar o gerenciamento de dependências do Spring Boot ". Portanto, vamos passar para a documentação do Spring Boot . Deixe-me esclarecer que não usamos o Spring Boot em si, mas apenas o Gerenciamento de Dependências do Spring Boot. Ou seja, o projeto Spring Boot pode fornecer conhecimento sobre quais versões de bibliotecas usar (incluindo Spring MVC). Lá encontraremos 3.2. Usando o gerenciamento de dependências do Spring Boot isoladamente . De acordo com a documentação, adicione o seguinte ao script de construção:plugins {
id 'org.springframework.boot' version '2.0.4.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
E
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
Como você pode ver, indicamos apply false
, ou seja, Não usamos o Spring Boot em si, mas usamos o gerenciamento de dependências a partir daí. Esse gerenciamento de dependências também é chamado de BOM – “ Bill Of Materials ”. Agora estamos prontos para conectar o próprio projeto Spring Web MVC. Spring Web MVC faz parte do projeto Spring Framework e estamos interessados na seção " Web Servlet ". Vamos adicionar a dependência ao script de construção: compile 'org.springframework:spring-webmvc'
. Como podemos ver, definimos o escopo compile, porque o servidor web não nos fornece o Spring. Nosso projeto é forçado a incluir a biblioteca Spring dentro de si. A seguir, é importante lermos a seção " 1.2. DispatcherServlet ", onde é dito que o Spring MVC é construído em torno do padrão " Front controller ", onde existe uma espécie de servlet central que fornece configuração e delegação para outros componentes . Dispatcher pode ser traduzido como despachante. Então, antes de mais nada, em web.xml declaramos:
applicationContext.xml
que especificamos anteriormente. Vejamos um exemplo da documentação do Spring: " 1.10.3. Detectando automaticamente classes e registrando definições de bean ".
-
Configuração da Web, por exemplo, configuração de estilo Java:
@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp("/WEB-INF/pages/", ".jsp"); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
Este exemplo está descrito na documentação do Spring Framework: " 1.11. MVC Config ".
Aqui registramos um ViewResolver, que ajudará a determinar onde as páginas jsp estão localizadas. O segundo método garante que o " servlet padrão " esteja habilitado.
Você pode ler mais sobre isso aqui: " Qual é a necessidade e uso do default-servlet-handler ".
-
Controlador HelloController para descrever o mapeamento de solicitações para um JSP específico
@Controller public class HelloController { @GetMapping("/hello") public String handle(Model model) { return "hello"; } }
Aqui usamos a anotação @Controller descrita na documentação do capítulo " 1.4. Controladores anotados ".
/webproject/hello
(onde /webproject é a raiz de contexto), o DispatcherServlet será processado primeiro. Ele, como despachante principal, determinará que /* corresponde à solicitação atual, o que significa que o DispatcherServlet deve fazer alguma coisa. Em seguida, ele passará por todos os mapeamentos que encontrar. Ele verá que existe um HelloController com um método handle mapeado para /hello e o executará. Este método retornará o texto "olá". Este texto será recebido pelo ViewResolver, que informará ao servidor onde procurar os arquivos jsp que precisam ser exibidos ao cliente. Assim, o cliente acabará por receber aquela página tão querida.
GO TO FULL VERSION