Ответ 1
Поместите класс сервлета в package
Прежде всего, поместите класс сервлета в Java package
. Вы всегда должны публиковать повторно используемые классы Java в пакете, иначе они невидимы для классов, которые находятся в пакете, таких как сам сервер. Таким образом вы устраняете потенциальные проблемы, связанные с окружающей средой. Пакетные сервлеты работают только в определенных комбинациях Tomcat + JDK, и на это никогда не следует полагаться.
В случае "простого" проекта IDE класс должен быть помещен в структуру пакета внутри папки "Ресурсы Java" и, следовательно, не "WebContent", это для веб файлов, таких как JSP. Ниже приведен пример структуры папок по умолчанию Eclipse Dynamic Web Project, как показано в представлении Navigator:
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
В случае проекта Maven класс должен быть помещен в его структуру пакета внутри main/java
и, таким образом, нет, например. main/resources
, это для файлов неклассов. Ниже приведен пример структуры папок проекта Maven Webapp по умолчанию, как показано в представлении Eclipse Navigator:
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Обратите внимание, что подпапка /jsps
не является строго необходимой. Вы даже можете обойтись без него и поставить JSP файл прямо в webcontent/webapp root, но я просто беру на себя это из вашего вопроса.
Установить URL сервлета в url-pattern
URL-адрес сервлета задается как "шаблон URL" для отображения сервлета. Это абсолютно не для определения имени класса/имени класса сервлета. Шаблон URL должен быть указан как значение аннотации @WebServlet
.
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.
// ...
}
Если вы хотите поддерживать параметры пути, такие как /servlet/foo/bar
, вместо этого используйте шаблон URL /servlet/*
. См. Также параметры сервлета и пути, такие как /xyz/ {value}/test, как отобразить в web.xml?
@WebServlet
работает только на Servlet 3.0 или новее
Чтобы использовать @WebServlet
, вам нужно только убедиться, что ваш файл web.xml
, если он есть (он по умолчанию с сервлета 3.0), объявлен совместимым с версией Servlet 3.0+ и, следовательно, не соответствуют, например 2.5 или ниже. Ниже приведен совместимый с Servlet 3.1 (который соответствует Tomcat 8+, WildFly 8+, GlassFish 4+ и т.д.).
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1"
>
<!-- Config here. -->
</web-app>
Или, если вы еще не используете Servlet 3.0+ (а не Tomcat 7 или новее, но Tomcat 6 или старше), удалите аннотацию @WebServlet
.
package com.example;
public class YourServlet extends HttpServlet {
// ...
}
И зарегистрируйте сервлет вместо этого в web.xml
следующим образом:
<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>
Обратите внимание, что вы не должны использовать оба способа. Используйте либо конфигурацию на основе аннотаций, либо конфигурацию на основе XML. Если у вас есть оба варианта, то настройка на основе XML будет переопределять конфигурацию на основе аннотаций.
Проверка сборки/развертывания
Если вы используете инструмент построения, такой как Eclipse и/или Maven, то вам нужно обязательно убедиться, что файл класса скомпилированного сервлета находится в его структуре пакета в папке /WEB-INF/classes
созданного файла WAR. В случае package com.example; public class YourServlet
он должен быть расположен в /WEB-INF/classes/com/example/YourServlet.class
. В противном случае вы столкнетесь с @WebServlet
также ошибкой 404 или в случае <servlet>
ошибки HTTP 500, как показано ниже:
Состояние HTTP 500
Ошибка создания экземпляра класса сервлета com.example.YourServlet
И найдите в журнале сервера java.lang.ClassNotFoundException: com.example.YourServlet
, а затем java.lang.NoClassDefFoundError: com.example.YourServlet
, а затем javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
.
Простой способ проверить, правильно ли скомпилирован сервлет и поместить его в путь к классам, чтобы позволить инструменту сборки создать WAR файл (например, проект rightclick, Export > WAR файл в Eclipse), а затем проверить его содержимое с помощью инструмента ZIP. Если в /WEB-INF/classes
отсутствует класс сервлета, проект плохо настроен или некоторые настройки по умолчанию для IDE/проекта были ошибочно возвращены (например, Project > Build Automatically отключен в Eclipse). Если у вас нет подсказки, лучше всего перезапустить с нуля и не трогать никакие настройки конфигурации IDE/проекта.
Тестирование сервлета отдельно
При условии, что сервер работает на localhost:8080
и что WAR успешно развернут по пути контекста /contextname
(который по умолчанию соответствует имени проекта IDE, чувствителен к регистру!), и сервлет не удался инициализация (чтение журналов сервера для любых сообщений об успешном/неудачном развертывании/сервлете, фактический путь контекста и отображение сервлета), тогда сервлет с шаблоном URL-адреса /servlet
доступен в http://localhost:8080/contextname/servlet
.
Вы можете просто ввести его прямо в адресную строку браузера, чтобы проверить его invidivually. Если его doGet()
правильно переопределен и реализован, вы увидите его вывод в браузере. Или, если у вас нет doGet()
или если он неправильно вызывает super.doGet()
, то этот URL-адрес HTTP 405: HTTP GET не поддерживается этим URL" будет отображаться ошибка (которая по-прежнему лучше, чем 404, поскольку 405 свидетельствует о том, что сам сервлет действительно найден).
Переопределение service()
- это плохая практика, если вы не изобретаете структуру MVC и— что очень маловероятно, если вы только начинаете работу с сервлетами и не знаете, что связано с проблемой, описанной в текущем вопросе;) См. также Веб-приложения с шаблонами проектирования.
Независимо, если сервлет уже возвращает 404 при проверке invidivually, тогда совершенно бессмысленно пытаться использовать HTML-форму. Логически, поэтому также совершенно бессмысленно включать любую форму HTML в вопросы о 404 ошибках сервлета.
Ссылка на URL сервлета из HTML
Как только вы подтвердили, что сервлет отлично работает при вызове по отдельности, вы можете перейти к HTML. Что касается вашей конкретной проблемы с формой HTML, значение <form action>
должно быть допустимым URL. То же самое относится к <a href>
. Вам нужно понять, как работают абсолютные/относительные URL-адреса. Вы знаете, что URL-адрес является веб-адресом, поскольку вы можете ввести/увидеть в адресной строке веб-браузера. Если вы указываете относительный URL-адрес как действие формы, то есть без схемы http://
, тогда он становится относительно текущего URL-адреса, как вы видите в строке адреса веб-браузера. Таким образом, это абсолютно не относится к расположению файла JSP/HTML в структуре папок WAR WAR, как кажется многим начинающим.
Итак, предполагая, что страница JSP с формой HTML открывается http://localhost:8080/contextname/jsps/page.jsp
, и вам нужно отправить сервлет, расположенный в http://localhost:8080/contextname/servlet
, вот несколько случаев (обратите внимание, что вы можете спокойно заменить <form action>
на <a href>
здесь):
-
Действие формы отправляется в URL с ведущей косой чертой.
<form action="/servlet">
Ведущая косая черта
/
делает URL-адрес относительно домена, поэтому форма будет отправляться наhttp://localhost:8080/servlet
Но это, скорее всего, приведет к 404, поскольку оно находится в неправильном контексте.
-
Действие формы отправляется в URL без косой черты.
<form action="servlet">
Это делает URL-адрес относительно текущей папки текущего URL-адреса, поэтому форма будет отправлена на
http://localhost:8080/contextname/jsps/servlet
Но это, скорее всего, приведет к 404, поскольку он находится в неправильной папке.
-
Действие формы отправляется на URL-адрес, который идет одной папкой вверх.
<form action="../servlet">
Это переместит одну папку вверх (точно так же, как в пути к локальной файловой системе на диске!), поэтому форма будет отправлена на
http://localhost:8080/contextname/servlet
Это должно работать!
-
Однако канонический подход заключается в том, чтобы сделать относительный URL-адрес таким образом, что вам не нужно снова исправлять URL-адреса, когда вы перемещаете JSP файлы в другую папку.
<form action="${pageContext.request.contextPath}/servlet">
Это приведет к созданию
<form action="/contextname/servlet">
Таким образом, он всегда будет отправлен на правильный URL.
Используйте прямые кавычки в HTML
Вам нужно убедиться, что вы используете прямые кавычки в атрибутах HTML, таких как action="..."
или action='...'
и, следовательно, не фигурные кавычки, такие как action="..."
или action=’...’
. Кудрявые кавычки не поддерживаются в HTML, и они просто станут частью значения.
См. также:
- Страница наших сервлетов wiki - содержит несколько примеров приветствия
- Как вызвать класс сервлета из HTML-формы
- doGet и doPost в сервлетах
- Как передать текущий элемент методу Java, нажав гиперссылку или кнопку на странице JSP?
Другие случаи ошибки HTTP Status 404:
- Статус HTTP 404 - Сервлет [имя сервлета] недоступен
- Статус HTTP 404 - Запрошенный ресурс (/Имя_проекта/) недоступен
- Статус HTTP 404 - Запрошенный ресурс (/) недоступен
- JSP in/WEB-INF возвращает "HTTP-статус 404 Запрошенный ресурс недоступен"
- Ссылка на ресурс, размещенный в папке WEB-INF в файле JSP, возвращает HTTP 404 на ресурсе
- Браузер не может получать/находить относительные ресурсы, такие как CSS, изображения и ссылки при вызове сервлета, который пересылает JSP.