Aplikasi Spring MVC standar Anda akan melayani semua permintaan melalui DispatcherServletyang telah Anda daftarkan dengan container Servlet Anda.
The DispatcherServletterlihat di perusahaan ApplicationContextdan, jika tersedia, ApplicationContextterdaftar dengan ContextLoaderListenerbiji khusus perlu untuk setup permintaannya melayani logika. Kacang ini dijelaskan dalam dokumentasi .
Bisa dibilang yang paling penting, kacang HandlerMappingpeta tipe
permintaan masuk ke penangan dan daftar pemroses sebelum dan sesudah (penangan penangan) berdasarkan beberapa kriteria yang rinciannya berbeda-beda menurut HandlerMappingpenerapan. Implementasi yang paling populer mendukung pengontrol beranotasi, tetapi implementasi lain juga ada.
The javadoc dariHandlerMapping lebih lanjut menjelaskan bagaimana implementasi harus berperilaku.
The DispatcherServletmenemukan semua kacang jenis ini dan register mereka dalam beberapa urutan (dapat disesuaikan). Saat melayani permintaan, DispatcherServletloop melalui HandlerMappingobjek - objek ini dan menguji masing-masing objek dengan getHandleruntuk menemukan satu yang dapat menangani permintaan masuk, direpresentasikan sebagai standar HttpServletRequest. Pada 4.3.x, jika tidak menemukannya , ia mencatat peringatan yang Anda lihat
Tidak ada pemetaan ditemukan untuk permintaan HTTP dengan URI [/some/path]di DispatcherServletdengan nama somename
dan baik melemparkan NoHandlerFoundExceptionatau segera melakukan respon dengan kode status 404 Not Found.
Mengapa tidak DispatcherServletmenemukan HandlerMappingyang bisa menangani permintaan saya?
HandlerMappingImplementasi yang paling umum adalah RequestMappingHandlerMapping, yang menangani pendaftaran @Controllerkacang sebagai penangan (sebenarnya @RequestMappingmetode beranotasi mereka ). Anda dapat mendeklarasikan kacang jenis ini sendiri (dengan @Beanatau <bean>atau mekanisme lain) atau Anda dapat menggunakan opsi bawaan . Ini adalah:
- Beri anotasi pada
@Configurationkelas Anda dengan @EnableWebMvc.
- Deklarasikan
<mvc:annotation-driven />anggota dalam konfigurasi XML Anda.
Seperti yang dijelaskan tautan di atas, keduanya akan mendaftarkan RequestMappingHandlerMappingkacang (dan banyak hal lainnya). Namun, a HandlerMappingtidak terlalu berguna tanpa pawang. RequestMappingHandlerMappingmengharapkan beberapa @Controllerbean sehingga Anda perlu mendeklarasikannya juga, melalui @Beanmetode dalam konfigurasi Java atau <bean>deklarasi dalam konfigurasi XML atau melalui pemindaian komponen @Controllerkelas beranotasi di keduanya. Pastikan kacang ini ada.
Jika Anda mendapatkan pesan peringatan dan 404 dan telah mengonfigurasi semua hal di atas dengan benar, maka Anda mengirimkan permintaan Anda ke URI yang salah , yang tidak ditangani oleh @RequestMappingmetode penangan beranotasi yang terdeteksi .
The spring-webmvcpenawaran perpustakaan lain built-in HandlerMappingimplementasi. Misalnya, BeanNameUrlHandlerMappingpeta
dari URL ke kacang dengan nama yang dimulai dengan garis miring ("/")
dan Anda selalu bisa menulis sendiri. Jelas, Anda harus memastikan permintaan yang Anda kirim cocok dengan setidaknya salah satu HandlerMappingpenangan objek terdaftar .
Jika Anda tidak secara implisit atau eksplisit mendaftarkan HandlerMappingkacang apa pun (atau jika detectAllHandlerMappingsada true), DispatcherServletregister beberapa default . Ini didefinisikan dalam DispatcherServlet.propertiespaket yang sama dengan DispatcherServletkelas. Mereka adalah BeanNameUrlHandlerMappingdan DefaultAnnotationHandlerMapping(yang serupa RequestMappingHandlerMappingtetapi tidak digunakan lagi).
Debugging
MVC Spring akan mencatat penangan yang terdaftar melalui RequestMappingHandlerMapping. Misalnya, @Controllersuka
@Controller
public class ExampleController {
@RequestMapping(path = "/example", method = RequestMethod.GET, headers = "X-Custom")
public String example() {
return "example-view-name";
}
}
akan mencatat berikut ini di tingkat INFO
Mapped "{[/example],methods=[GET],headers=[X-Custom]}" onto public java.lang.String com.spring.servlet.ExampleController.example()
Ini menggambarkan pemetaan yang terdaftar. Jika Anda melihat peringatan bahwa tidak ada penangan yang ditemukan, bandingkan URI dalam pesan dengan pemetaan yang tercantum di sini. Semua batasan yang ditentukan dalam @RequestMappingharus cocok untuk Spring MVC untuk memilih penangan.
HandlerMappingImplementasi lain mencatat pernyataan mereka sendiri yang seharusnya mengisyaratkan pemetaan mereka dan penangannya yang sesuai.
Demikian pula, aktifkan pencatatan Musim Semi pada tingkat DEBUG untuk melihat kacang mana yang didaftarkan Spring. Itu harus melaporkan kelas beranotasi mana yang ditemukannya, paket mana yang dipindai, dan kacang mana yang diinisialisasi. Jika yang Anda harapkan tidak ada, tinjau ApplicationContextkonfigurasi Anda .
Kesalahan umum lainnya
A DispatcherServlethanyalah Java EE tipikal Servlet. Anda mendaftar dengan khas <web.xml> <servlet-class>dan <servlet-mapping>deklarasi, atau langsung melalui ServletContext#addServletdalam WebApplicationInitializer, atau dengan mekanisme apapun yang menggunakan Musim Semi booting. Karena itu, Anda harus mengandalkan pemetaan url logika ditentukan dalam spesifikasi Servlet , lihat Bab 12. Lihat juga
Dengan mengingat hal tersebut, kesalahan umum adalah mendaftarkan DispatcherServletdengan pemetaan url /*, mengembalikan nama tampilan dari a@RequestMapping metode penangan, dan mengharapkan JSP untuk dirender. Misalnya, pertimbangkan metode penangan seperti
@RequestMapping(path = "/example", method = RequestMethod.GET)
public String example() {
return "example-view-name";
}
dengan sebuah InternalResourceViewResolver
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver vr = new InternalResourceViewResolver();
vr.setPrefix("/WEB-INF/jsps/");
vr.setSuffix(".jsp");
return vr;
}
Anda mungkin mengharapkan permintaan diteruskan ke sumber daya JSP di jalur /WEB-INF/jsps/example-view-name.jsp. Ini tidak akan terjadi. Sebaliknya, dengan asumsi nama konteksExample , DisaptcherServletakan melaporkan
Tidak ada pemetaan yang ditemukan untuk permintaan HTTP dengan URI [/Example/WEB-INF/jsps/example-view-name.jsp]diDispatcherServlet dengan nama 'operator'
Karena DispatcherServletdipetakan ke /*dan /*cocok dengan semuanya (kecuali kecocokan persis, yang memiliki prioritas lebih tinggi), DispatcherServletakan dipilih untuk menangani forwarddari JstlView(dikembalikan oleh InternalResourceViewResolver). Di hampir setiap kasus, DispatcherServlettidak akan dikonfigurasi untuk menangani permintaan seperti itu .
Sebaliknya, dalam kasus sederhana ini, Anda harus mendaftarkan DispatcherServletke /, menandainya sebagai servlet default. Servlet default adalah kecocokan terakhir untuk permintaan. Ini akan memungkinkan wadah servlet khas Anda untuk memilih implementasi Servlet internal, yang dipetakan ke*.jsp , untuk menangani sumber daya JSP (misalnya, Tomcat memiliki JspServlet), sebelum mencoba dengan servlet default.
Itulah yang Anda lihat dalam contoh Anda.