JavaRush /Blogue Java /Random-PT /Criando uma aplicação web simples usando servlets e jsp (...
Стас Пасинков
Nível 26
Киев

Criando uma aplicação web simples usando servlets e jsp (parte 1)

Publicado no grupo Random-PT
Nível de conhecimento necessário para entender o artigo: você já entendeu mais ou menos o Java Core e gostaria de dar uma olhada nas tecnologias JavaEE e na programação web. Faz mais sentido se você estiver estudando atualmente a missão Java Collections, que cobre tópicos próximos ao artigo. Criando uma aplicação web simples usando servlets e jsp (parte 1) - 1Este material é uma continuação lógica do meu artigo Criando um projeto web simples no IntelliJ Idea Enterprise . Nele demonstrei como criar um modelo de projeto web funcional. Desta vez, mostrarei como criar uma aplicação web simples, mas bonita, usando as tecnologias Java Servlet API e JavaServer Pages API. Nosso aplicativo terá uma página inicial com dois links:
  • para a página de adição de usuário;
  • para a página de visualização da lista de usuários.
Ainda usarei o IntelliJ Idea Enterprise Edition, o Apache Maven (inclui apenas algumas dependências) e o Apache Tomcat. Ao final iremos “decorar” nossa aplicação utilizando o framework W3.CSS . Assumiremos que neste momento você já possui um projeto vazio, que iremos desenvolver aqui. Se não, leia o primeiro artigo e faça-o. Isso levará apenas alguns minutos :)

Um pouco sobre a estrutura do futuro aplicativo

Nossa página principal ( / ) será a página html estática mais comum com um cabeçalho e dois links/botões:
  • adicione um novo usuário (será enviado para /add );
  • visualizar a lista de usuários (envia para /list ).
O Tomcat irá capturar solicitações para esses endereços e enviá-las para um dos dois servlets que faremos (descreveremos o mapeamento no arquivo web.xml ). E os servlets, por sua vez, processarão as solicitações, prepararão os dados (ou os salvarão se um usuário for adicionado) e transferirão o controle para os arquivos jsp correspondentes, que já “renderizarão” o resultado. Armazenaremos os dados na lista mais comum (List).

Vamos criar uma página inicial estática

Se você tiver index.jsp em sua pasta web , exclua-o. Em vez disso, nesta pasta criaremos um arquivo html simples chamado index.html :
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My super project!</title>
</head>
<body>
    <!-- header -->
    <div>
        <h1>Super app!<//h1>
    </div>

    <div>       <!-- content -->
        <div>    <!-- buttons holder -->
            <button onclick="location.href='/list'">List users<//button>
            <button onclick="location.href='/add'">Add user<//button>
        </div>
    </div>
</body>
</html>
Não há nada complicado aqui. No título indicamos o título da nossa página. No corpo da página temos duas divs principais: header (cabeçalho) e conteúdo (conteúdo). No conteúdo temos um suporte para nossos botões, e na verdade dois botões que, ao serem clicados, são enviados para os endereços apropriados. Você pode executar o projeto e ver como está agora. Se você clicar nos botões, páginas com erro 404 serão abertas porque ainda não as temos. Mas isso sugere que os botões funcionam. Deixe-me observar que esta não é a opção mais universal, porque se você desabilitar repentinamente o JavaScript, esses botões não terão utilidade no navegador. Mas vamos assumir que ninguém desabilitou o JavaScript :). É claro que links simples podem ser usados, mas prefiro botões. Você faz o que mais gosta. E não olhe para o fato de que nos meus exemplos haverá muitos divs . Depois vamos preenchê-los com estilos, e tudo ficará mais bonito :).

Crie arquivos jsp para renderizar o resultado

No mesmo diretório web criaremos uma pasta onde colocaremos nossos arquivos jsp . Chamei isso de visualizações e, novamente, você pode improvisar. Nesta pasta criaremos dois arquivos jsp:
  • add.jsp — página para adição de usuários;
  • list.jsp - página para exibir uma lista de usuários.
Vamos dar-lhes os títulos de página apropriados. Algo como “Adicionar novo usuário” e “Lista de usuários”, e deixaremos assim por enquanto.

Vamos criar dois servlets

Os servlets aceitarão e processarão solicitações que o Tomcat passará para eles. Na pasta src/main/java criaremos um pacote de aplicativos , que conterá nossos fontes. Lá teremos mais pacotes diferentes. Portanto, para que esses pacotes não sejam criados uns dentro dos outros, vamos criar alguma classe no pacote app (depois excluí-la). Agora vamos criar três pacotes diferentes no pacote app :
  • entidades - é aqui que nossas entidades ficarão (a própria classe, que descreverá os objetos do usuário);
  • modelo - nosso modelo estará aqui (mais sobre isso mais tarde);
  • servlets - bem, aqui estarão nossos servlets.
Depois disso, você pode remover com segurança essa classe do pacote do aplicativo (se você a criou, é claro). Vamos criar duas classes no pacote servlets :
  • AddServlet - processará as solicitações recebidas em /add ;
  • ListServlet - processará as solicitações recebidas em /list .

Conectando dependências no Maven

O Tomcat versão 9.* implementa as especificações do Servlet versão 4.0 e do JavaServer Pages versão 2.3. Isso está escrito na documentação oficial do Tomcat 9 no primeiro parágrafo da segunda linha. Isso significa que se você, como eu, estiver usando esta versão do Tomcat, então o código que escrevemos e enviamos para execução usará exatamente as versões especificadas. Mas gostaríamos de ter essas especificações em nosso projeto, para que nosso código que as utiliza seja pelo menos compilado com sucesso. E para isso precisamos carregá-los em nosso projeto. É aqui que Maven vem em socorro.

A regra geral é esta: se você precisar conectar algo ao seu projeto usando Maven:

  • acesse o site do repositório Maven;
  • procure lá a biblioteca que você precisa e a versão que você precisa;
  • você obtém o código de dependência que precisa ser inserido em seu pom.xml;
  • inserir! :)
Então vamos começar. Primeiro, vamos preparar um arquivo pom . Em algum lugar depois de /version mas antes de /project , insira o seguinte:
<dependencies>

</dependencies>
Assim, indicamos que dentro dessas tags listaremos as dependências que necessitamos. Agora vá para mvnrepository.com , haverá um campo de pesquisa no topo. Primeiro, insira servlet na pesquisa. O primeiro resultado, onde são mais de sete mil utilizações, nos convém. Lembramos que precisamos da versão 4.0 (para Tomcat 9; para outras versões, implementações mais antigas podem ser adequadas). Esta é uma versão bastante recente, portanto não há muitos usos, mas é o que precisamos. Será aberta uma página onde você pode obter o código desta dependência para vários gerenciadores de pacotes e você pode até mesmo baixá-lo. Mas como queremos conectá-lo usando Maven, selecionamos o código na aba Maven. Copiamos e colamos em nosso arquivo pom dentro da seção de dependências. Se aparecer uma notificação no canto inferior direito do IDEA perguntando se queremos ativar a importação automática, concordamos. Se você recusou acidentalmente, vá em “Configurações” e habilite a importação automática manualmente: Configurações (Ctrl + Alt + S) -> Build, Execution, Deployment -> Maven -> Importing Isso manterá o arquivo pom e os arquivos de configuração IDEA para isso projeto em sincronia. Agora, usando o mesmo princípio, encontraremos e conectaremos o JavaServer Pages versão 2.3 (insira jsp na pesquisa). E como já adotamos o Maven, vamos dizer imediatamente que nossos fontes estão em conformidade com a sintaxe do Java 8 e que precisam ser compilados em bytecode da mesma versão. Depois de todas essas manipulações, nosso pom.xml ficará mais ou menos assim:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ru.javarush.info.fatfaggy</groupId>
    <artifactId>my-super-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compile.source>
        <maven.compiler.target>1.8</maven.compile.target>
    </properties>

    <dependencies>
        <!-- Servlet API 4.0 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JavaServer Pages API 2.3 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

Tornando nossos servlets servlets reais

Neste ponto, os dois servlets que criamos são, na verdade, apenas classes regulares. Eles não têm nenhuma funcionalidade. Mas agora conectamos a API do Servlet ao nosso projeto e, se sim, podemos usar classes a partir daí. Para tornar nossos servlets servlets “reais”, simplesmente precisamos herdá-los da classe HttpServlet .

Mapeamento ou particionamento

Agora seria bom dizer de alguma forma ao Tomcat para que as solicitações de /add sejam tratadas pelo nosso servlet AddServlet e, portanto, as solicitações de /list sejam tratadas pelo servlet ListServlet . Este processo é chamado de mapeamento . Isso é feito no arquivo web.xml de acordo com este princípio:
  • primeiro descrevemos o servlet (damos algum nome e indicamos o caminho para a própria classe);
  • em seguida, vinculamos esse servlet a um endereço específico (indicamos o nome do servlet que acabamos de fornecer e indicamos o endereço de onde as solicitações devem ser enviadas para este servlet).
Vamos descrever o servlet:
<servlet>
    <servlet-name>add</servlet-name>
    <servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
Agora vinculamos ao endereço:
<servlet-mapping>
    <servlet-name>add</servlet-name>
    <url-pattern>/add</url-pattern>
</servlet-mapping>
Como você pode ver, o nome do servlet é o mesmo em ambos os casos. Graças a isso, o Tomcat sabe que se uma solicitação chegar ao endereço /add , ela precisará ser passada para o servlet app.servlets.AddServlet . Fazemos o mesmo com o segundo servlet. Como resultado, nosso web.xml possui aproximadamente o seguinte conteúdo:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- add servlet -->
    <servlet>
        <servlet-name>add</servlet-name>
        <servlet-class>app.servlets.AddServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>add</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>

    <!-- list servlet -->
    <servlet>
        <servlet-name>list</servlet-name>
        <servlet-class>app.servlets.ListServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>list</servlet-name>
        <url-pattern>/list</url-pattern>
    </servlet-mapping>
</web-app>
A propósito, não criamos marcação para a página principal aqui (em / ). O fato é que neste caso não precisamos disso. Nossa página inicial é um arquivo HTML simples que exibe apenas dois botões. Não há conteúdo dinâmico, então não faz sentido criarmos um servlet separado para ele, para o qual serão enviadas solicitações do endereço / , e que não fará nada além de transferir a execução para algum jsp (que também teria que ser criado), que desenharia se tivéssemos dois botões. Não precisamos disso; estamos satisfeitos com um recurso estático. Quando o Tomcat receber uma solicitação, ele verificará se não há um único servlet que possa processar a solicitação nesse endereço e, em seguida, verá que esse endereço realmente contém um arquivo html pronto , que ele enviará com sucesso . Podemos executar nossa aplicação novamente (reiniciar o servidor ou reimplantar, como desejar) e ter certeza de que a página principal está renderizada, nada está quebrado, quando clicamos nos botões ocorrem transições, mas por enquanto um erro também é escrito. Aliás, se antes tínhamos um erro 404, agora temos um 405. Isso significa que o mapeamento funcionou, os servlets foram encontrados, mas eles simplesmente não tinham métodos adequados para processar a solicitação. Se nesta fase você ainda receber um erro 404, embora tudo tenha sido feito corretamente, talvez você deva corrigir a configuração de implantação na ideia. Para fazer isso, você precisa ir em Editar configurações (na parte superior perto do botão Iniciar), ir até a aba Deployment no lado direito da janela e certificar-se de que no contexto do Aplicativo está simplesmente indicado /

Uma breve digressão lírica: o que está acontecendo “nos bastidores”?

Você provavelmente já se perguntou como funciona nossa aplicação no Tomcat? O que está acontecendo lá? E onde está o método main() ? Assim que você digitar localhost:8080 em seu navegador e acessar este endereço, o navegador enviará uma solicitação para este endereço através do protocolo http . Espero que você já esteja ciente de que as solicitações podem ser de diferentes “tipos”, sendo os mais populares GET e POST . Toda solicitação deve ter uma resposta. A solicitação GET espera que, em resposta, seja fornecido um código html pronto , que será retornado ao navegador, e o navegador substituirá lindamente esse código por todos os tipos de letras, botões e formulários. A solicitação POST é um pouco mais interessante, pois também carrega consigo algumas informações. Por exemplo, no formulário de cadastro ou autorização do usuário, você inseriu seus dados e clicou em “enviar”. Neste momento, uma solicitação POST foi enviada ao servidor contendo suas informações pessoais. O servidor aceitou essas informações, processou-as e retornou algum tipo de resposta (por exemplo, uma página html com o seu perfil). A diferença fundamental entre eles é que as solicitações GET destinam-se apenas a receber dados do servidor, enquanto as solicitações POST carregam algumas informações com elas, e os dados no servidor podem mudar (por exemplo, quando você carrega sua foto no servidor, ela voará na requisição POST e o servidor irá adicioná-la ao banco de dados, ou seja, ocorrerá alguma alteração. Agora vamos voltar ao Tomcat. Quando ele recebe alguma requisição do cliente, ele olha o endereço. Pesquisa seus dados para veja se existe um servlet adequado, que processe solicitações para tal endereço (ou um recurso pronto que possa ser retornado imediatamente).Se não encontrar nada para retornar, ele não responderá com uma página html, mas com uma resposta 404. Se encontrar um servlet adequado, que "fica" neste endereço, ele verifica que tipo de solicitação recebeu (GET, POST ou algum outro) e então pergunta ao servlet se ele possui um método que poderia lidar com esse tipo de solicitação. Se o servlet disser que não pode processar esse tipo, o Tomcat responde ao cliente com o código 405. Isso é o que aconteceu conosco. Mas se um servlet adequado for encontrado e tiver um método adequado, o Tomcat cria um objeto desse servlet, executa-o em um novo thread ( thread ), que permite que o servlet funcione em um thread separado, e o Tomcat continua a trabalhar mais por conta própria, recebendo e enviando solicitações. Além disso, o Tomcat cria mais dois objetos: um do tipo HttpServletRequest (vou chamá-lo brevemente de solicitação no futuro) e o segundo do tipo HttpServletResponse(vou chamar isso de resposta). No primeiro objeto ele coloca todos os dados que recebeu em uma solicitação do cliente, para que todos esses dados possam ser retirados deste objeto. Bom, depois de tudo isso, ele passa esses dois objetos para o método apropriado do servlet que está rodando em uma thread separada. Assim que o servlet termina seu trabalho e tem uma resposta pronta para enviar ao cliente, ele levanta um sinalizador para o Tomcat, dizendo: “Terminei, está tudo pronto”. O Tomcat aceita a resposta e a envia ao cliente. Isso permite que o Tomcat aceite solicitações e envie respostas sem interrupção, enquanto todo o trabalho é feito por servlets executados em threads separados. Conseqüentemente, quando escrevemos o código do servlet, definimos o trabalho que será executado. E sim, você pode pensar no método main() como estando no próprio Tomcat (sim, está escrito em Java), e quando "iniciamos" o Tomcat, o arquivo main().

Capturamos métodos GET com servlets e enviamos respostas simples

No momento, nossos servlets não possuem métodos adequados (GET), então o Tomcat nos retorna um erro 405. Vamos fazê-los! A classe HttpServlet , da qual herdamos nossos servlets, define diferentes métodos. Para definir algum código para métodos, simplesmente os substituímos. Neste caso, precisamos substituir o método doGet() em ambos os servlets.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}
Como você pode ver, este método aceita dois objetos: req (solicitação) e resp (resposta). Esses são os objetos que o Tomcat criará e preencherá para nós quando chamar o método apropriado neste servlet. Primeiro, vamos fazer as respostas mais simples. Para fazer isso, pegue o objeto resp e obtenha dele um objeto PrintWriter , que pode ser usado para compor respostas. Bem, usando-o imprimiremos uma string simples.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter();
    writer.println("Method GET from AddServlet");
}
Faremos algo semelhante no servlet ListServlet , após o qual iniciaremos nosso servidor novamente. Como você pode ver, tudo funciona! Ao clicar nos botões, abrem-se páginas com o texto que “gravamos” com PrintWriter . Só que nosso jsp que preparamos para gerar páginas com respostas não é utilizado de forma alguma. Isso ocorre porque a execução simplesmente não os atinge. O próprio serverlet agora gera uma resposta e finaliza seu trabalho, sinalizando ao Tomcat que possui uma resposta pronta para o cliente. O Tomcat simplesmente pega essa resposta e a envia de volta ao cliente. Transferimos o controle dos servlets para jsp. Vamos alterar o código dos nossos métodos desta forma:
  • obtemos do objeto request um objeto gerenciador de solicitações, onde passamos o endereço jsp da página para a qual queremos transferir o controle;
  • usando o objeto recebido, transferimos o controle para a página jsp especificada e não se esqueça de anexar lá os objetos de solicitação e resposta que recebemos do Tomcat.
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
    requestDispatcher.forward(req, resp);
}
No corpo das páginas jsp (dentro da tag body) podemos escrever algo para que possamos ver claramente qual página está sendo exibida. Depois disso, reiniciamos o servidor e verificamos. Os botões da página principal são pressionados, as páginas são abertas, o que significa que as solicitações são enviadas aos servlets, após o que o controle é transferido para as páginas jsp, que já estão renderizadas. Isso é tudo. Na próxima parte do artigo trataremos da funcionalidade de nossa aplicação.

O que mais ler:

Criando um projeto web simples no IntelliJ Idea Enterprise. Passo a passo, com fotos


Meu bate-papo
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION