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 /jspssubpasta 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 @WebServletanotaçã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.xmlarquivo, 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 @WebServletanotação.
package com.example;
public class YourServlet extends HttpServlet {
// ...
}
E registre o servlet web.xmlassim:
<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/classespasta 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 @WebServlettambé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/classesou 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:8080e 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 /servletestá 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.jspe 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: