Coloque a classe servlet em um package
Em primeiro lugar, coloque a classe servlet em um Java package
. Você deve sempre colocar classes Java reutilizáveis publicamente em um pacote, caso contrário, elas são invisíveis para as classes que estão em um pacote, como o próprio servidor. Dessa forma, você elimina possíveis problemas específicos do ambiente. Servlets sem pacote funcionam apenas em combinações específicas de Tomcat + JDK e nunca se deve confiar nisso.
No caso de um projeto IDE "simples", a classe precisa ser colocada em sua estrutura de pacote dentro da pasta "Recursos Java" e, portanto, não "Conteúdo da Web", isto é para arquivos da web como JSP. Abaixo está um exemplo da estrutura de pastas de um projeto da Web dinâmico Eclipse padrão , conforme visto na visualização do Navegador :
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
No caso de um projeto Maven, a classe precisa ser colocada em sua estrutura de pacote dentro main/java
e, portanto, nãomain/resources
, por exemplo , isso é para arquivos não pertencentes à classe . Abaixo está um exemplo da estrutura de pastas de um projeto Maven webapp padrão, conforme visto na visualização Navigator do Eclipse :
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Observe que a /jsps
subpasta não é estritamente necessária. Você pode até mesmo prescindir dele e colocar o arquivo JSP diretamente na raiz webcontent / webapp, mas estou apenas retomando sua pergunta.
Definir o URL do servlet em url-pattern
O URL do servlet é especificado como o "padrão de URL" do mapeamento do servlet. Não é absolutamente por definição o nome da classe / nome do arquivo da classe servlet. O padrão de URL deve ser especificado como valor de @WebServlet
anotação.
package com.example; // Use a package!
@WebServlet("/servlet") // This is the URL of the servlet.
public class YourServlet extends HttpServlet { // Must be public and extend HttpServlet.
// ...
}
Caso queira oferecer suporte a parâmetros de caminho como /servlet/foo/bar
, use um padrão de URL de /servlet/*
. Veja também Servlet e parâmetros de caminho como / xyz / {value} / test, como mapear em web.xml?
@WebServlet
funciona apenas no Servlet 3.0 ou mais recente
Para usar @WebServlet
, você só precisa se certificar de que seu web.xml
arquivo, se houver (é opcional desde o Servlet 3.0), é declarado conforme a versão Servlet 3.0+ e, portanto, não conforme, por exemplo, versão 2.5 ou inferior . Abaixo está um Servlet 4.0 compatível (que combina com Tomcat 9+, WildFly 11+, Payara 5+, etc).
<?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_4_0.xsd"
version="4.0"
>
<!-- Config here. -->
</web-app>
Ou, caso você ainda não esteja no Servlet 3.0+ (por exemplo, Tomcat 6 ou mais antigo), remova a @WebServlet
anotação.
package com.example;
public class YourServlet extends HttpServlet {
// ...
}
E registre o servlet web.xml
assim:
<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>com.example.YourServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>yourServlet</servlet-name>
<url-pattern>/servlet</url-pattern> <!-- This is the URL of the servlet. -->
</servlet-mapping>
Observe, portanto, que você não deve usar as duas maneiras. Use configuração baseada em anotação ou configuração baseada em XML. Quando você tiver ambos, a configuração baseada em XML substituirá a configuração baseada em anotação.
Verificando a construção / implantação
Caso você esteja usando uma ferramenta de construção como Eclipse e / ou Maven, você precisa ter certeza absoluta de que o arquivo de classe do servlet compilado reside em sua estrutura de pacote na /WEB-INF/classes
pasta do arquivo WAR produzido. No caso de package com.example; public class YourServlet
, deve estar localizado em /WEB-INF/classes/com/example/YourServlet.class
. Caso contrário, você enfrentará no caso de @WebServlet
também um erro 404, ou no caso de <servlet>
um erro HTTP 500 como abaixo:
HTTP Status 500
Erro ao instanciar a classe de servlet com.example.YourServlet
E localize no log do servidor a java.lang.ClassNotFoundException: com.example.YourServlet
, seguido por a java.lang.NoClassDefFoundError: com.example.YourServlet
, por sua vez seguido por javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
.
Uma maneira fácil de verificar se o servlet está compilado corretamente e colocado no classpath é permitir que a ferramenta de construção produza um arquivo WAR (por exemplo, clique com o botão direito do mouse em projeto, Exportar> arquivo WAR no Eclipse) e inspecione seu conteúdo com uma ferramenta ZIP. Se a classe do servlet estiver ausente /WEB-INF/classes
ou se a exportação causar um erro, o projeto está mal configurado ou alguns padrões de configuração do IDE / projeto foram revertidos por engano (por exemplo, Projeto> Compilar automaticamente foi desativado no Eclipse).
Você também precisa se certificar de que o ícone do projeto não tem uma cruz vermelha indicando um erro de construção. Você pode encontrar o erro exato na visualização Problemas ( Janela> Mostrar Visualização> Outro ... ). Normalmente, a mensagem de erro é boa Googlable. Caso você não tenha ideia, o melhor é reiniciar do zero e não tocar em nenhum padrão de configuração de IDE / projeto. Caso esteja usando o Eclipse, você pode encontrar instruções em Como faço para importar a API javax.servlet no meu projeto Eclipse?
Testando o servlet individualmente
Contanto que o servidor seja executado localhost:8080
e o WAR seja implantado com sucesso em um caminho de contexto /contextname
(cujo padrão é o nome do projeto IDE, diferencia maiúsculas de minúsculas!) E o servlet não falhou em sua inicialização (leia os logs do servidor para qualquer implantação / mensagens de sucesso / falha do servlet e o caminho de contexto real e mapeamento do servlet), então um servlet com padrão de URL de /servlet
está disponível em http://localhost:8080/contextname/servlet
.
Você pode simplesmente inseri-lo diretamente na barra de endereços do navegador para testá-lo individualmente. Se doGet()
for substituído e implementado corretamente, você verá sua saída no navegador. Ou se você não tiver nenhum doGet()
ou se ele chamar incorretamente super.doGet()
, um erro " HTTP 405: o método HTTP GET não é compatível com este URL " será mostrado (que ainda é melhor do que um 404, pois um 405 é uma evidência de que o servlet se é realmente encontrado).
Substituir service()
é uma prática ruim, a menos que você esteja reinventando uma estrutura MVC - o que é muito improvável se você está apenas começando com servlets e não tem noção do problema descrito na pergunta atual;) Consulte também Aplicativos baseados na web de Padrões de Design .
Independentemente disso, se o servlet já retorna 404 quando testado individualmente, então é totalmente inútil tentar com um formulário HTML. Logicamente, portanto, também é totalmente inútil incluir qualquer formulário HTML em perguntas sobre erros 404 de um servlet.
Referência ao URL do servlet em HTML
Depois de verificar se o servlet funciona bem quando invocado individualmente, você pode avançar para o HTML. Quanto ao seu problema concreto com o formulário HTML, o <form action>
valor precisa ser um URL válido. O mesmo se aplica a <a href>
. Você precisa entender como funcionam os URLs absolutos / relativos. Você sabe, um URL é um endereço da web que você pode inserir / ver na barra de endereços do navegador. Se você estiver especificando uma URL relativa como ação de formulário, ou seja, sem o http://
esquema, ela se tornará relativa à URL atual, conforme você vê na barra de endereços do navegador. Portanto, não é absolutamente relativo à localização do arquivo JSP / HTML na estrutura de pastas WAR do servidor, como muitos iniciantes parecem pensar.
Portanto, supondo que a página JSP com o formulário HTML seja aberta por http://localhost:8080/contextname/jsps/page.jsp
e você precise enviar a um servlet localizado em http://localhost:8080/contextname/servlet
, aqui estão vários casos (observe que você pode substituir <form action>
com segurança por <a href>
aqui):
A ação do formulário é enviada para um URL com uma barra inicial.
<form action="/servlet">
A barra inicial /
torna o URL relativo ao domínio, portanto, o formulário será enviado para
http://localhost:8080/servlet
Mas isso provavelmente resultará em um 404, pois está no contexto errado.
A ação do formulário é enviada para um URL sem uma barra inicial.
<form action="servlet">
Isso torna o URL relativo à pasta atual do URL atual, portanto, o formulário será enviado para
http://localhost:8080/contextname/jsps/servlet
Mas isso provavelmente resultará em um 404, pois está na pasta errada.
A ação do formulário é submetida a um URL que sobe uma pasta.
<form action="../servlet">
Isso irá subir uma pasta (exatamente como nos caminhos do sistema de arquivos do disco local!), Portanto, o formulário será enviado para
http://localhost:8080/contextname/servlet
Este deve funcionar!
A abordagem canônica, entretanto, é tornar a URL relativa ao domínio, para que você não precise corrigir as URLs novamente quando mover os arquivos JSP para outra pasta.
<form action="${pageContext.request.contextPath}/servlet">
Isso vai gerar
<form action="/contextname/servlet">
Que, portanto, sempre enviará para o URL correto.
Use aspas retas em HTML
Você precisa ter certeza absoluta de que está usando aspas retas em atributos HTML como action="..."
ou action='...'
e, portanto, não aspas curvas como action=”...”
ou action=’...’
. Aspas curtas não são suportadas em HTML e simplesmente se tornarão parte do valor.
Veja também:
Outros casos de erro HTTP Status 404: