2017-01-10 13 views
51

Tôi đang viết một ứng dụng Spring MVC, được triển khai trên Tomcat. Xem sau minimal, complete, and verifiable example:Tại sao Spring MVC phản hồi bằng 404 và báo cáo "Không có ánh xạ nào được tìm thấy cho yêu cầu HTTP với URI [...] trong DispatcherServlet"?

public class Application extends AbstractAnnotationConfigDispatcherServletInitializer { 
    protected Class<?>[] getRootConfigClasses() { 
     return new Class<?>[] { }; 
    } 
    protected Class<?>[] getServletConfigClasses() { 
     return new Class<?>[] { SpringServletConfig.class }; 
    } 
    protected String[] getServletMappings() { 
     return new String[] { "/*" }; 
    } 
} 

đâu SpringServletConfig

@Configuration 
@ComponentScan("com.example.controllers") 
@EnableWebMvc 
public class SpringServletConfig { 
    @Bean 
    public InternalResourceViewResolver resolver() { 
     InternalResourceViewResolver vr = new InternalResourceViewResolver(); 
     vr.setPrefix("/WEB-INF/jsps/"); 
     vr.setSuffix(".jsp"); 
     return vr; 
    } 
} 

Cuối cùng, tôi có một @Controller trong gói com.example.controllers

@Controller 
public class ExampleController { 
    @RequestMapping(path = "/home", method = RequestMethod.GET) 
    public String example() { 
     return "index"; 
    } 
} 

tên bối cảnh ứng dụng của tôi là Example. Khi tôi gửi một yêu cầu đến

http://localhost:8080/Example/home 

ứng dụng đáp ứng với một trạng thái HTTP 404 và ghi lại sau

WARN o.s.web.servlet.PageNotFound - No mapping found for HTTP request with URI `[/Example/WEB-INF/jsps/index.jsp]` in `DispatcherServlet` with name 'dispatcher' 

Tôi có một nguồn JSP tại /WEB-INF/jsps/index.jsp tôi mong đợi Spring MVC sử dụng bộ điều khiển của tôi để xử lý yêu cầu và chuyển tiếp đến JSP, vậy tại sao nó phản hồi với 404?


Đây có thể là một bài đăng chuẩn cho các câu hỏi về thông báo cảnh báo này.

Trả lời

48

Ứ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

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à:

  1. Chú thích @Configuration lớp học với @EnableWebMvc.
  2. 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 detectAllHandlerMappingstrue), 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à BeanNameUrlHandlerMappingDefaultAnnotationHandlerMapping (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><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'

DispatcherServlet được ánh xạ tới /*/* 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.

+0

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? –

+0

@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. –

+0

@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? –

0

Tôi đã gặp một lý do khác cho cùng một lỗi. Điều này cũng có thể là do các tệp lớp không được tạo cho tệp controller.java của bạn. Kết quả là servlet dispatcher được đề cập trong web.xml không thể ánh xạ nó tới phương thức thích hợp trong lớp điều khiển.

@Controller 
Class Controller{ 
@RequestMapping(value="/abc.html")//abc is the requesting page 
public void method() 
{.....} 
} 

Trong nhật thực dưới dự án-> chọn sạch -> Xây dựng Project.Do cung cấp cho một tấm séc nếu tập tin lớp đã được tạo ra cho tập tin điều khiển dưới xây dựng trong không gian làm việc của bạn.

2

tôi giải quyết vấn đề của tôi khi ngoài việc được mô tả trước: `

@Bean 
public InternalResourceViewResolver resolver() { 
    InternalResourceViewResolver vr = new InternalResourceViewResolver(); 
    vr.setPrefix("/WEB-INF/jsps/"); 
    vr.setSuffix(".jsp"); 
    return vr; 
} 

added tomcat-embed-jasper:

<dependency> 
     <groupId>org.apache.tomcat.embed</groupId> 
     <artifactId>tomcat-embed-jasper</artifactId> 
     <scope>provided</scope> 
</dependency> 

' từ: JSP file not rendering in Spring Boot web application

Các vấn đề liên quan