Đặt lớp servlet trong một package
Trước hết, đặt lớp servlet trong Java package
. Bạn phải luôn luôn đặt các lớp Java có thể sử dụng lại công khai trong một gói, nếu không chúng vô hình với các lớp trong một gói, chẳng hạn như chính máy chủ. Bằng cách này, bạn sẽ loại bỏ các vấn đề môi trường cụ thể tiềm năng. Các gói dịch vụ không đóng gói chỉ hoạt động trong các kết hợp Tomcat + JDK cụ thể và điều này không bao giờ nên được dựa vào.
Trong trường hợp dự án IDE "đơn giản", lớp cần được đặt trong cấu trúc gói của nó bên trong thư mục "Tài nguyên Java" và do đó không phải là "WebContent", đây là cho các tệp web như JSP. Dưới đây là một ví dụ về cấu trúc thư mục của Dự án Web động Eclipse mặc định như được thấy trong khung nhìn Navigator :
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Trong trường hợp của một dự án Maven, lớp cần được đặt trong cấu trúc gói của nó bên trong main/java
và do đó không phải là ví dụ main/resources
, đây là cho các tệp không phải là lớp . Dưới đây là một ví dụ về cấu trúc thư mục của dự án ứng dụng web Maven mặc định như được thấy trong khung nhìn Navigator của Eclipse :
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Lưu ý rằng /jsps
thư mục con không thực sự cần thiết. Bạn thậm chí có thể làm mà không cần nó và đặt tệp JSP trực tiếp vào root webcontent / webapp, nhưng tôi chỉ tiếp nhận điều này từ câu hỏi của bạn.
Đặt URL servlet trong url-pattern
URL servlet được chỉ định là "mẫu URL" của ánh xạ servlet. Nó hoàn toàn không theo định nghĩa tên lớp / tên tệp của lớp servlet. Mẫu URL sẽ được chỉ định làm giá trị của @WebServlet
chú thích.
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.
// ...
}
Trong trường hợp bạn muốn hỗ trợ các tham số đường dẫn như thế /servlet/foo/bar
, thì hãy sử dụng mẫu URL /servlet/*
thay thế. Xem thêm Servlet và các tham số đường dẫn như / xyz / {value} / test, làm thế nào để ánh xạ trong web.xml?
@WebServlet
chỉ hoạt động trên Servlet 3.0 trở lên
Để sử dụng @WebServlet
, bạn chỉ cần đảm bảo rằng web.xml
tệp của bạn , nếu có (tùy chọn kể từ Servlet 3.0), được khai báo tuân thủ phiên bản Servlet 3.0+ và do đó không tuân thủ phiên bản 2.5 trở xuống . Dưới đây là một phiên bản tương thích Servlet 3.1 (phù hợp với Tomcat 8+, WildFly 8+, GlassFish 4+, v.v.).
<?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>
Hoặc, trong trường hợp bạn chưa có trên Servlet 3.0+ (không phải Tomcat 7 hoặc mới hơn, mà là Tomcat 6 trở lên), sau đó xóa @WebServlet
chú thích.
package com.example;
public class YourServlet extends HttpServlet {
// ...
}
Và đăng ký servlet thay vì web.xml
như thế này:
<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>
Lưu ý do đó bạn không nên sử dụng cả hai cách. Sử dụng cấu hình dựa trên chú thích hoặc cấu hình dựa trên XML. Khi bạn có cả hai, thì cấu hình dựa trên XML sẽ ghi đè cấu hình dựa trên chú thích.
Xác minh việc xây dựng / triển khai
Trong trường hợp bạn đang sử dụng một công cụ xây dựng như Eclipse và / hoặc Maven, thì bạn cần chắc chắn rằng tệp lớp servlet đã biên dịch nằm trong cấu trúc gói của nó trong /WEB-INF/classes
thư mục của tệp WAR được tạo. Trong trường hợp package com.example; public class YourServlet
, nó phải được đặt tại /WEB-INF/classes/com/example/YourServlet.class
. Nếu không, bạn sẽ phải đối mặt trong trường hợp @WebServlet
cũng có lỗi 404 hoặc trong trường hợp <servlet>
có lỗi HTTP 500 như dưới đây:
Trạng thái HTTP 500
Lỗi khởi tạo lớp servlet com.example.YourServlet
Và tìm trong máy chủ đăng nhập a java.lang.ClassNotFoundException: com.example.YourServlet
, theo sau là a java.lang.NoClassDefFoundError: com.example.YourServlet
, lần lượt theo sau javax.servlet.ServletException: Error instantiating servlet class com.example.YourServlet
.
Một cách dễ dàng để xác minh xem servlet có được biên dịch và đặt chính xác trong đường dẫn lớp hay không là để công cụ xây dựng tạo ra một tệp WAR (ví dụ: dự án rightclick, xuất> tệp WAR trong Eclipse) và sau đó kiểm tra nội dung của nó bằng công cụ ZIP. Nếu lớp servlet bị thiếu /WEB-INF/classes
, thì dự án bị cấu hình kém hoặc một số mặc định cấu hình IDE / dự án đã bị hoàn nguyên nhầm (ví dụ: Project> Build Automatic đã bị vô hiệu hóa trong Eclipse). Trong trường hợp bạn không có đầu mối, tốt nhất là khởi động lại từ đầu và không chạm vào bất kỳ mặc định cấu hình IDE / dự án nào.
Kiểm tra từng servlet
Với điều kiện là máy chủ chạy localhost:8080
và WAR được triển khai thành công trên đường dẫn ngữ cảnh /contextname
(mặc định là tên dự án IDE, phân biệt chữ hoa chữ thường!) Và servlet đã không khởi tạo được nó (đọc nhật ký máy chủ cho bất kỳ triển khai / Các thông báo thành công / thất bại của servlet và đường dẫn ngữ cảnh thực tế và ánh xạ servlet), sau đó một servlet có mẫu URL /servlet
có sẵn tại http://localhost:8080/contextname/servlet
.
Bạn chỉ có thể nhập thẳng vào thanh địa chỉ của trình duyệt để kiểm tra nó một cách vô tình. Nếu nó doGet()
được ghi đè và thực hiện đúng, thì bạn sẽ thấy đầu ra của nó trong trình duyệt. Hoặc nếu bạn không có bất kỳ doGet()
hoặc nếu nó gọi không chính xác super.doGet()
, thì lỗi " HTTP 405: HTTP phương thức GET không được hỗ trợ bởi URL này " sẽ được hiển thị (vẫn tốt hơn 404 vì 405 là bằng chứng cho thấy servlet chính nó thực sự được tìm thấy).
Ghi đè service()
là một thực tiễn tồi, trừ khi bạn phát minh lại khung MVC - điều này rất khó xảy ra nếu bạn chỉ mới bắt đầu với các máy chủ và không biết gì về vấn đề được mô tả trong câu hỏi hiện tại;) Xem thêm Thiết kế ứng dụng dựa trên web .
Bất kể, nếu servlet đã trả về 404 khi được kiểm tra một cách vô tình, thì việc thử với biểu mẫu HTML hoàn toàn vô nghĩa. Về mặt logic, do đó, hoàn toàn vô nghĩa khi đưa bất kỳ biểu mẫu HTML nào vào các câu hỏi về lỗi 404 từ một servlet.
Tham chiếu URL servlet từ HTML
Khi bạn đã xác minh rằng servlet hoạt động tốt khi được gọi riêng lẻ, thì bạn có thể chuyển sang HTML. Đối với vấn đề cụ thể của bạn với biểu mẫu HTML, <form action>
giá trị cần phải là một URL hợp lệ. Áp dụng tương tự cho <a href>
. Bạn cần hiểu cách URL tuyệt đối / tương đối hoạt động. Bạn biết đấy, một URL là một địa chỉ web mà bạn có thể nhập / xem trong thanh địa chỉ của webbrowser. Nếu bạn chỉ định một URL tương đối dưới dạng hành động biểu mẫu, tức là không có http://
lược đồ, thì nó sẽ trở thành tương đối với URL hiện tại như bạn thấy trong thanh địa chỉ của webbrowser. Do đó, nó hoàn toàn không liên quan đến vị trí tệp tin JSP / HTML trong cấu trúc thư mục WAR của máy chủ như nhiều người mới bắt đầu nghĩ.
Vì vậy, giả định rằng các trang web với các hình thức HTML JSP được mở ra bởi http://localhost:8080/contextname/jsps/page.jsp
, và bạn cần phải nộp cho một servlet nằm trong http://localhost:8080/contextname/servlet
, sau đây là một vài trường hợp (lưu ý rằng bạn có thể yên tâm thay thế <form action>
với <a href>
ở đây):
Hành động biểu mẫu gửi đến một URL với dấu gạch chéo hàng đầu.
<form action="/servlet">
Dấu gạch chéo hàng đầu /
làm cho URL liên quan đến tên miền, do đó biểu mẫu sẽ được gửi tới
http://localhost:8080/servlet
Nhưng điều này có thể sẽ dẫn đến một 404 vì nó trong bối cảnh sai.
Hành động biểu mẫu gửi đến một URL mà không có dấu gạch chéo hàng đầu.
<form action="servlet">
Điều này làm cho URL liên quan đến thư mục hiện tại của URL hiện tại, do đó biểu mẫu sẽ được gửi tới
http://localhost:8080/contextname/jsps/servlet
Nhưng điều này có thể sẽ dẫn đến một 404 vì nó nằm trong thư mục sai.
Hành động biểu mẫu gửi đến một URL đi lên một thư mục.
<form action="../servlet">
Điều này sẽ đi lên một thư mục (chính xác như trong đường dẫn hệ thống tệp đĩa cục bộ!), Do đó biểu mẫu sẽ được gửi tới
http://localhost:8080/contextname/servlet
Cái này phải làm việc!
Tuy nhiên, cách tiếp cận chính tắc là làm cho tên miền URL trở nên tương đối để bạn không cần sửa URL một lần nữa khi bạn tình cờ di chuyển các tệp JSP xung quanh vào một thư mục khác.
<form action="${pageContext.request.contextPath}/servlet">
Điều này sẽ tạo ra
<form action="/contextname/servlet">
Do đó sẽ luôn luôn gửi đúng URL.
Sử dụng dấu ngoặc kép trong HTML
Bạn cần chắc chắn rằng bạn đang sử dụng dấu ngoặc kép thẳng trong các thuộc tính HTML như action="..."
hoặc action='...'
do đó không phải là dấu ngoặc kép như action=”...”
hoặc action=’...’
. Dấu ngoặc kép không được hỗ trợ trong HTML và chúng sẽ đơn giản trở thành một phần của giá trị.
Xem thêm:
Các trường hợp khác của lỗi Trạng thái HTTP 404:
phiên bản ứng dụng web = "3.1" bằng cách sử dụng cá thủy tinh, tôi có thể kiểm tra riêng servlet của mình chỉ tốt khi tôi có ánh xạ trong tệp web.xml VÀ chú thích. Tôi đã xóa ánh xạ và để lại chú thích vì tôi có phiên bản mới nhất nhưng sau đó tôi sẽ gặp lỗi 404?
– Hoàng Kim Hương 13:54:56 14/03/2018Điều đó có thể xảy ra nếu bạn bao gồm các thư viện servlet 2.5 trở lên trong chính ứng dụng web thay vì dựa vào thời gian chạy đích để tự cung cấp các thư viện servlet.
– Bùi Phương Giang 14:19:13 14/03/2018
– Trịnh Nguyên Hồng 17:48:53 06/04/2019<form action="../servlet">
không hoạt động trong trường hợp của tôi ...@xdola: Nó thực sự dễ vỡ vì nó phụ thuộc vào URI yêu cầu. Chỉ cần đọc câu trả lời cho lời giải thích về vấn đề của bạn và cách tiếp cận đúng là gì.
– Hoàng Việt Hồng 11:17:46 08/04/2019