Ứng dụng Spring MVC tiêu chuẩn của bạn sẽ phục vụ tất cả các yêu cầu thông qua một DispatcherServlet
mà bạn đã đăng ký với vùng chứa Servlet của mình.
Cái DispatcherServlet
nhìn vào nó ApplicationContext
và, nếu có, được ApplicationContext
đăng ký với một ContextLoaderListener
hạt đậu đặc biệt, nó cần thiết lập logic phục vụ yêu cầu của nó. Những hạt đậu này được mô tả trong tài liệu .
Được cho là quan trọng nhất, đậu của loại HandlerMapping
bản đồ
các yêu cầu đến trình xử lý và danh sách các trình xử lý trước và sau (trình đánh chặn trình xử lý) dựa trên một số tiêu chí, chi tiết của chúng khác nhau tùy theo cách 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 cũng tồn tại.
Các javadoc củaHandlerMapping
thêm mô tả cách triển khai phải cư xử.
Tìm DispatcherServlet
thấy 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ục vụ một yêu cầu, các DispatcherServlet
vòng lặp qua các HandlerMapping
đối tượng này và kiểm tra từng đối tượng getHandler
để tìm một đối tượng có thể xử lý yêu cầu đến, được biểu thị dưới dạng tiêu chuẩn HttpServletRequest
. Kể từ 4.3.x, nếu nó không tìm thấy bất kỳ , nó sẽ ghi lại cảnh báo mà bạ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à một trong hai ném một NoHandlerFoundException
hoặc ngay lập tức cam kết đáp ứng với một mã trạng thái 404 Not Found.
Tại sao không DispatcherServlet
tìm thấy một HandlerMapping
có thể xử lý yêu cầu của tôi?
Cách HandlerMapping
triển khai phổ biến nhất là RequestMappingHandlerMapping
xử lý việc đăng ký @Controller
bean dưới dạng trình xử lý (thực sự là các @RequestMapping
phương thức được chú thích của chúng ). Bạn có thể tự khai báo bean 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 các tùy chọn tích hợp sẵn . Đó là:
- Chú thích
@Configuration
lớp của bạn với @EnableWebMvc
.
- Khai báo một
<mvc:annotation-driven />
thành viên trong cấu hình XML của bạn.
Như liên kết ở trên mô tả, cả hai thứ này sẽ đăng ký một RequestMappingHandlerMapping
bean (và một loạt các thứ khác). Tuy nhiên, một HandlerMapping
không hữu ích lắm nếu không có một trình xử lý. RequestMappingHandlerMapping
mong đợi một số @Controller
bean, vì vậy bạn cũng cần phải khai báo chúng, thông qua @Bean
các phương thức trong cấu hình Java hoặc <bean>
khai báo trong cấu hình XML hoặc thông qua quét thành phần của @Controller
các lớp được chú thích trong một trong hai. Đảm bảo có những hạt đậu này.
Nếu bạn nhận được thông báo cảnh báo và mã 404 và bạn đã định cấu hình tất cả các điều trên một cách chính xác, thì bạn đang gửi yêu cầu của mình đến sai URI , một URI không được xử lý bằng @RequestMapping
phương pháp xử lý có chú thích được phát hiện .
Các spring-webmvc
Mời thư viện khác được xây dựng trong HandlerMapping
việc triển khai. Ví dụ, BeanNameUrlHandlerMapping
bản đồ
từ URL đến bean có tên bắt đầu bằng dấu gạch chéo ("/")
và bạn luôn có thể viết của riêng bạn. Rõ ràng, bạn sẽ phải đảm bảo rằng yêu cầu bạn đang gửi khớp với ít nhất một trong các HandlerMapping
trình xử lý của đối tượng đã đăng ký .
Nếu bạn không đăng ký ngầm định hoặc rõ ràng bất kỳ HandlerMapping
bean nào (hoặc nếu detectAllHandlerMappings
là true
), thì DispatcherServlet
đăng ký một số giá trị mặc định . Chúng được định nghĩa trong DispatcherServlet.properties
cùng một gói với DispatcherServlet
lớp. Chúng là BeanNameUrlHandlerMapping
và DefaultAnnotationHandlerMapping
(tương tự như RequestMappingHandlerMapping
nhưng không được dùng nữa).
Gỡ lỗi
Spring MVC sẽ ghi lại các trình xử lý đã đăng ký thông qua RequestMappingHandlerMapping
. Ví dụ, một @Controller
like
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
sẽ ghi lại những điều sau ở cấp độ INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Điều này mô tả ánh xạ đã đă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 giới hạn được chỉ định trong @RequestMapping
phải khớp với Spring MVC để chọn trình xử lý.
Các HandlerMapping
triển khai khác ghi lại các câu lệnh của riêng chúng mà sẽ gợi ý cho các á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 kích hoạt tính năng ghi nhật ký Spring ở mức GỠ LỖI để xem Spring đăng ký đậu nào. Nó sẽ báo cáo lớp được chú thích nào mà nó tìm thấy, gói nào nó quét và đậu nó khởi tạo. Nếu những cái bạn mong đợi không có, hãy xem lại ApplicationContext
cấu hình của bạn .
Những lỗi phổ biến khác
A DispatcherServlet
chỉ là một Java EE điển hình Servlet
. Bạn đăng ký nó với thông thường <web.xml>
<servlet-class>
và <servlet-mapping>
khai báo của bạn , hoặc trực tiếp thông qua ServletContext#addServlet
một WebApplicationInitializer
hoặc với bất kỳ cơ chế nào mà Spring boot sử dụng. Như vậy, bạn phải dựa vào logic ánh xạ url được chỉ định trong đặc tả Servlet , xem Chương 12. Xem thêm
Với ý nghĩ đó, một sai lầm phổ biến là đăng ký DispatcherServlet
ánh xạ url của /*
, trả về tên chế độ xem từ @RequestMapping
phương thức xử lý và mong đợi một JSP được hiển thị. Ví dụ: hãy xem xét một phương thức 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 yêu cầu được chuyển tiếp đến 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ử có tên ngữ cảnh là Example
, DisaptcherServlet
sẽ báo cáo
Không có ánh xạ tìm thấy cho HTTP yêu cầu với URI [/Example/WEB-INF/jsps/example-view-name.jsp]
trong DispatcherServlet
với tên 'phối'
Bởi vì dấu DispatcherServlet
được ánh xạ tới /*
và /*
khớp với mọi thứ (ngoại trừ các kết quả chính xác, có mức độ ưu tiên cao hơn), nên DispatcherServlet
sẽ được chọn để xử lý forward
từ JstlView
(được trả về bởi InternalResourceViewResolver
). Trong hầu hết mọi trường hợp, DispatcherServlet
sẽ không được cấu hình để xử lý một 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
tới /
, đánh dấu nó là servlet mặc định. Servlet mặc định là kết quả phù hợp cuối cùng cho một yêu cầu. Điều này sẽ cho phép vùng chứa servlet điển hình của bạn chọn một triển khai Servlet nội bộ, được á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 đang thấy trong ví dụ của mình.