Đặ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 đặ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 sẽ ẩn đối với các lớp nằm trong một gói, chẳng hạn như chính máy chủ. Bằng cách này, bạn loại bỏ các vấn đề tiềm ẩn về môi trường cụ thể. Các servlet khô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ờ được dựa vào.
Trong trường hợp là một dự án IDE "thuần túy", 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 "WebContent", điều này dành cho các tệp web như JSP. Dưới đây là 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 dạng xem Bộ điều hướng :
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 phải được đặt ở bên trong cấu trúc gói của nó main/java
và do đó không ví dụ main/resources
, đây là cho các tập tin không theo class . Dưới đây là 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 dạng xem Bộ điều hướng 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 hoàn toàn 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 webcontent / webapp root, nhưng tôi chỉ giải quyết vấn đề này từ câu hỏi của bạn.
Đặt URL của servlet trong url-pattern
URL của servlet được chỉ định là "mẫu URL" của ánh xạ servlet. Nó hoàn toàn không phải 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ư /servlet/foo/bar
, 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, cách ánh xạ trong web.xml?
@WebServlet
chỉ hoạt động trên Servlet 3.0 hoặc mới hơ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ó (nó là tùy chọn kể từ Servlet 3.0), được khai báo là phù hợp với phiên bản Servlet 3.0+ và do đó không tuân theo phiên bản 2.5 hoặc thấp hơn . Dưới đây là một tương thích Servlet 4.0 (phù hợp với Tomcat 9+, WildFly 11+, Payara 5+, v.v.).
<?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>
Hoặc, trong trường hợp bạn chưa sử dụng Servlet 3.0+ (ví dụ: Tomcat 6 trở lên), hãy xóa @WebServlet
chú thích.
package com.example;
public class YourServlet extends HttpServlet {
// ...
}
Và đăng ký servlet thay thế trong 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>
Do đó, lưu ý rằng 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 hoàn toàn đảm bảo 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 của 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ẽ gặp phải trường hợp @WebServlet
lỗi 404 hoặc trong trường hợp <servlet>
lỗi HTTP 500 như bên dưới:
Trạng thái HTTP 500
Lỗi khi khởi tạo lớp servlet com.example.YourServlet
Và tìm trong nhật ký máy chủ a java.lang.ClassNotFoundException: com.example.YourServlet
, tiếp theo là a java.lang.NoClassDefFoundError: com.example.YourServlet
, lần lượt theo sau là 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 chính xác và được đặt trong classpath hay không là để công cụ xây dựng tạo ra tệp WAR (ví dụ: dự án nhấp chuột phải, 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 thiếu lớp servlet /WEB-INF/classes
hoặc nếu quá trình xuất gây ra lỗi, thì dự án được định cấu hình sai hoặc một số mặc định cấu hình IDE / dự án đã bị hoàn nguyên một cách nhầm lẫn (ví dụ: Dự án> Xây dựng Tự động đã bị tắt trong Eclipse).
Bạn cũng cần đảm bảo rằng biểu tượng dự án không có chữ thập đỏ chỉ ra lỗi xây dựng. Bạn có thể tìm lỗi chính xác trong dạng xem Vấn đề ( Cửa sổ> Hiển thị Dạng xem> Khác ... ). Thông thường thông báo lỗi là tốt Googlable. Trong trường hợp bạn không có manh 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. Trong trường hợp bạn đang sử dụng Eclipse, bạn có thể tìm hướng dẫn trong Làm cách nào để nhập API javax.servlet vào dự án Eclipse của tôi?
Kiểm tra servlet riêng lẻ
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 thất bại (đọc nhật ký máy chủ cho bất kỳ triển khai nào / 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), thì một servlet với mẫu URL của /servlet
có sẵn tại http://localhost:8080/contextname/servlet
.
Bạn chỉ có thể nhập trực tiếp vào thanh địa chỉ của trình duyệt để kiểm tra nó một cách ẩn ý. Nếu nó doGet()
được ghi đè và triển khai đúng cách, 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ì URL này không hỗ trợ " HTTP 405: HTTP method GET " sẽ được hiển thị (vẫn tốt hơn 404 vì 405 là bằng chứng cho thấy servlet bản thân nó thực sự được tìm thấy).
Ghi đè service()
là một thực tiễn không tốt, trừ khi bạn đang phát minh lại khung MVC - điều này rất khó xảy ra nếu bạn mới bắt đầu với các servlet và không biết về vấn đề được mô tả trong câu hỏi hiện tại;) Xem thêm các ứng dụng dựa trên web của Design Patterns .
Bất kể, nếu servlet đã trả về 404 khi được kiểm tra một cách vô hình, thì việc thử với một biểu mẫu HTML thay thế là hoàn toàn vô nghĩa. Về mặt logic, do đó cũng hoàn toàn vô nghĩa nếu đư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 của 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ệ. Điều tương tự cũng áp dụng 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, URL là một địa chỉ web mà bạn có thể nhập / xem trong thanh địa chỉ của trình duyệt web. Nếu bạn đang chỉ định một URL tương đối làm hành động biểu mẫu, tức là không có http://
lược đồ, thì nó sẽ tương đối với URL hiện tại như bạn thấy trong thanh địa chỉ của trình duyệt web của mình. Do đó, nó hoàn toàn không liên quan đến vị trí tệp 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 dường như nghĩ.
Vì vậy, giả sử rằng trang JSP có biểu mẫu HTML được mở bởi http://localhost:8080/contextname/jsps/page.jsp
và bạn cần gửi đến một servlet nằm trong đó http://localhost:8080/contextname/servlet
, đây là một số trường hợp (lưu ý rằng bạn có thể thay thế một cách an toàn <form action>
bằng <a href>
đây):
Hành động biểu mẫu gửi đến một URL có dấu gạch chéo ở đầu.
<form action="/servlet">
Dấu gạch chéo ở đầu /
làm cho URL có liên quan đến tên miền, do đó biểu mẫu sẽ gửi đến
http://localhost:8080/servlet
Nhưng điều này có thể sẽ dẫn đến 404 vì nó ở trong ngữ 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 ở đầu.
<form action="servlet">
Điều này làm cho URL có liên quan đến thư mục hiện tại của URL hiện tại, do đó biểu mẫu sẽ gửi đến
http://localhost:8080/contextname/jsps/servlet
Nhưng điều này có thể sẽ dẫn đến 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">
Thao tác này sẽ đi lên một thư mục (giống hệt như trong đường dẫn hệ thống tệp đĩa cục bộ!), Do đó biểu mẫu sẽ gửi đến
http://localhost:8080/contextname/servlet
Cái này phải hoạt động!
Tuy nhiên, cách tiếp cận chuẩn là tạo tên miền URL tương đối để bạn không cần sửa lại các URL khi bạn tình cờ di chuyển các tệp JSP sang 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 gửi đến đú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='...'
và do đó không phải 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: