Ứng dụng Spring MVC chuẩn của bạn sẽ phục vụ tất cả các yêu cầu qua DispatcherServlet
mà bạn đã đăng ký với vùng chứa Servlet của mình.
DispatcherServlet
xem ApplicationContext
và nếu có, ApplicationContext
đã đăng ký với số ContextLoaderListener
cho hạt đặc biệt, nó cần thiết lập logic phân phối yêu cầu. These beans are described in the documentation.
Có thể cho rằng điều quan trọng nhất, đậu các loại HandlerMapping
đồ
yêu cầu đến để xử lý và một danh sách trước và sau xử lý (chặn xử lý) dựa trên một số tiêu chí các chi tiết trong đó khác nhau tùy theo HandlerMapping
triển khai. Việc triển khai phổ biến nhất hỗ trợ các bộ điều khiển được chú thích nhưng các triển khai khác tồn tại ở dạng .
javadoc of HandlerMapping
mô tả thêm về cách triển khai phải hoạt động.
DispatcherServlet
tìm tất cả các loại đậu thuộc loại này và đăng ký chúng theo một số thứ tự (có thể được tùy chỉnh). Trong khi phân phát yêu cầu, các vòng DispatcherServlet
thông qua các đối tượng HandlerMapping
này và kiểm tra từng đối tượng với getHandler
để tìm một yêu cầu có thể xử lý yêu cầu đến, được biểu thị dưới dạng tiêu chuẩn HttpServletRequest
. Tính đến 4.3.x, nếu nó không tìm thấy bất kỳ, nó logs the warning mà bạn nhìn thấy
Không có ánh xạ tìm thấy cho yêu cầu HTTP URI [/some/path]
trong DispatcherServlet
với tên somename
và either ném một NoHandlerFoundException
hoặc ngay lập tức cam kết phản hồi với mã trạng thái 404 Not Found.
Tại sao số điện thoại DispatcherServlet
không tìm thấy số HandlerMapping
có thể xử lý yêu cầu của tôi?
Phổ biến nhất HandlerMapping
thực hiện là RequestMappingHandlerMapping
, nơi quản lý việc đăng ký @Controller
đậu như xử lý (thực sự @RequestMapping
phương pháp chú thích của họ). Bạn có thể tự khai báo một loại đậu của loại này (với @Bean
hoặc <bean>
hoặc cơ chế khác) hoặc bạn có thể sử dụng the built-in options. Đây là:
- Chú thích
@Configuration
lớp học với @EnableWebMvc
.
- Khai báo thành viên
<mvc:annotation-driven />
trong cấu hình XML của bạn.
Khi liên kết ở trên mô tả, cả hai đều sẽ đăng ký một hạt RequestMappingHandlerMapping
(và một loạt các thứ khác). Tuy nhiên, một HandlerMapping
không phải là rất hữu ích mà không có một xử lý. RequestMappingHandlerMapping
mong đợi một số hạt là @Controller
vì vậy bạn cũng cần phải khai báo các phương thức đó theo phương thức @Bean
trong cấu hình Java hoặc khai báo <bean>
trong cấu hình XML hoặc thông qua quét thành phần của các lớp được chú thích trong một trong hai. Hãy chắc chắn rằng những hạt đậu này có mặt.
Nếu bạn nhận được thông báo cảnh báo và 404 và bạn đã định cấu hình tất cả các thông tin ở trên, thì bạn đang gửi yêu cầu của mình đến URI sai. @RequestMapping
phương thức xử lý chú thích.
Thư viện spring-webmvc
cung cấp các triển khai khác được xây dựng trong HandlerMapping
. Ví dụ, BeanNameUrlHandlerMapping
maps
từ các URL để đậu có tên bắt đầu bằng một dấu gạch chéo ("/")
và bạn luôn có thể viết riêng của bạn. Rõ ràng, bạn sẽ phải đảm bảo yêu cầu bạn đang gửi khớp với ít nhất một trong các trình xử lý đối tượng đã đăng ký của HandlerMapping
.
Nếu bạn không rõ ràng hoặc ngầm đăng ký bất kỳ HandlerMapping
đậu (hoặc nếu detectAllHandlerMappings
là true
), các thanh ghi DispatcherServlet
một số defaults. Các giá trị này được xác định trong DispatcherServlet.properties
trong cùng một gói với lớp DispatcherServlet
. Chúng là BeanNameUrlHandlerMapping
và DefaultAnnotationHandlerMapping
(tương tự như RequestMappingHandlerMapping
nhưng không được chấp nhận).
Gỡ lỗi
Spring MVC sẽ ghi nhật ký xử lý thông qua RequestMappingHandlerMapping
. Ví dụ, một @Controller
như
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
sẽ đăng nhập như sau ở cấp INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
này mô tả các bản đồ đã đăng ký. Khi bạn thấy cảnh báo rằng không tìm thấy trình xử lý nào, hãy so sánh URI trong thông báo với ánh xạ được liệt kê ở đây. Tất cả các hạn chế được chỉ định trong @RequestMapping
phải khớp với Spring MVC để chọn trình xử lý.
Các triển khai khác HandlerMapping
ghi lại các câu lệnh của riêng chúng, nên gợi ý ánh xạ của chúng và các trình xử lý tương ứng của chúng.
Tương tự, hãy bật Ghi nhật ký ở mức DEBUG để xem những hạt đậu nào đăng ký. Nó sẽ báo cáo các lớp chú thích mà nó tìm thấy, các gói nào nó quét và các hạt mà nó khởi tạo. Nếu những thứ bạn mong đợi không có, hãy xem lại cấu hình ApplicationContext
của bạn.
sai lầm phổ biến khác
Một DispatcherServlet
chỉ là một điển hình Java EE Servlet
. Bạn đăng ký nó với tờ khai số <web.xml>
<servlet-class>
và <servlet-mapping>
điển hình của mình hoặc trực tiếp thông qua ServletContext#addServlet
trong một WebApplicationInitializer
hoặc với bất kỳ cơ chế khởi động Spring nào. Như vậy, bạn phải dựa vào url mapping lý theo quy định tại các Servlet specification, xem Chương 12. Xem thêm
Với ý nghĩ đó, một sai lầm phổ biến là đăng ký DispatcherServlet
với ánh xạ url là /*
, trả về tên chế độ xem từ phương thức xử lý @RequestMapping
và mong đợi kết xuất JSP. Ví dụ, hãy xem xét một phương pháp xử lý như
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
với một InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
bạn có thể mong đợi các yêu cầu để được forwarded tới một tài nguyên JSP tại đường dẫn /WEB-INF/jsps/example-view-name.jsp
. Điều này sẽ không xảy ra. Thay vào đó, giả sử một tên bối cảnh Example
, các DisaptcherServlet
sẽ báo cáo
Không có ánh xạ tìm thấy cho yêu cầu HTTP URI [/Example/WEB-INF/jsps/example-view-name.jsp]
trong DispatcherServlet
với tên 'phối'
Vì DispatcherServlet
được ánh xạ tới /*
và /*
khớp với mọi thứ (ngoại trừ các kết hợp chính xác, có mức độ ưu tiên cao hơn), số DispatcherServlet
sẽ được chọn để xử lý forward
từ số JstlView
(được trả về bởi InternalResourceViewResolver
).Trong hầu hết mọi trường hợp, DispatcherServlet
sẽ không được định cấu hình để xử lý yêu cầu như vậy. Thay vào đó, trong trường hợp đơn giản này, bạn nên đăng ký DispatcherServlet
đến /
, đánh dấu nó là servlet mặc định. Servlet mặc định là đối sánh cuối cùng cho một yêu cầu. Điều này sẽ cho phép thùng chứa servlet điển hình của bạn chọn một triển khai Servlet bên trong, ánh xạ tới *.jsp
, để xử lý tài nguyên JSP (ví dụ, Tomcat có JspServlet
), trước khi thử với servlet mặc định.
Đó là những gì bạn thấy trong ví dụ của mình.
Làm thế nào bạn có thể" đăng ký DispatcherServlet đến /, đánh dấu nó như servlet mặc định. " ? Bạn có thể chia sẻ đoạn mã này không? –
@SaifMasadeh Nếu bạn nhìn vào liên kết đặc tả Servlet trong câu trả lời (hoặc bài viết SO bên dưới nó), bạn sẽ thấy '/' là một ánh xạ đặc biệt cho các thùng chứa servlet, chỉ ra servlet "mặc định", sẽ được chọn nếu không có ánh xạ nào khác được khớp. –
@SotiriosDelimanolis Bạn có thể vui lòng xem qua repo github mà tôi đã tạo https://github.com/saifmasadeh/WeatherBoard/blob/master/src/main/java/com/demo/controller/RootController.java? –