Aplikasi Spring MVC standar Anda akan melayani semua permintaan melalui DispatcherServlet
yang telah Anda daftarkan dengan container Servlet Anda.
The DispatcherServlet
terlihat di perusahaan ApplicationContext
dan, jika tersedia, ApplicationContext
terdaftar dengan ContextLoaderListener
biji khusus perlu untuk setup permintaannya melayani logika. Kacang ini dijelaskan dalam dokumentasi .
Bisa dibilang yang paling penting, kacang HandlerMapping
peta tipe
permintaan masuk ke penangan dan daftar pemroses sebelum dan sesudah (penangan penangan) berdasarkan beberapa kriteria yang rinciannya berbeda-beda menurut HandlerMapping
penerapan. Implementasi yang paling populer mendukung pengontrol beranotasi, tetapi implementasi lain juga ada.
The javadoc dariHandlerMapping
lebih lanjut menjelaskan bagaimana implementasi harus berperilaku.
The DispatcherServlet
menemukan semua kacang jenis ini dan register mereka dalam beberapa urutan (dapat disesuaikan). Saat melayani permintaan, DispatcherServlet
loop melalui HandlerMapping
objek - objek ini dan menguji masing-masing objek dengan getHandler
untuk 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 DispatcherServlet
dengan nama somename
dan baik melemparkan NoHandlerFoundException
atau segera melakukan respon dengan kode status 404 Not Found.
Mengapa tidak DispatcherServlet
menemukan HandlerMapping
yang bisa menangani permintaan saya?
HandlerMapping
Implementasi yang paling umum adalah RequestMappingHandlerMapping
, yang menangani pendaftaran @Controller
kacang sebagai penangan (sebenarnya @RequestMapping
metode beranotasi mereka ). Anda dapat mendeklarasikan kacang jenis ini sendiri (dengan @Bean
atau <bean>
atau mekanisme lain) atau Anda dapat menggunakan opsi bawaan . Ini adalah:
- Beri anotasi pada
@Configuration
kelas Anda dengan @EnableWebMvc
.
- Deklarasikan
<mvc:annotation-driven />
anggota dalam konfigurasi XML Anda.
Seperti yang dijelaskan tautan di atas, keduanya akan mendaftarkan RequestMappingHandlerMapping
kacang (dan banyak hal lainnya). Namun, a HandlerMapping
tidak terlalu berguna tanpa pawang. RequestMappingHandlerMapping
mengharapkan beberapa @Controller
bean sehingga Anda perlu mendeklarasikannya juga, melalui @Bean
metode dalam konfigurasi Java atau <bean>
deklarasi dalam konfigurasi XML atau melalui pemindaian komponen @Controller
kelas 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 @RequestMapping
metode penangan beranotasi yang terdeteksi .
The spring-webmvc
penawaran perpustakaan lain built-in HandlerMapping
implementasi. Misalnya, BeanNameUrlHandlerMapping
peta
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 HandlerMapping
penangan objek terdaftar .
Jika Anda tidak secara implisit atau eksplisit mendaftarkan HandlerMapping
kacang apa pun (atau jika detectAllHandlerMappings
ada true
), DispatcherServlet
register beberapa default . Ini didefinisikan dalam DispatcherServlet.properties
paket yang sama dengan DispatcherServlet
kelas. Mereka adalah BeanNameUrlHandlerMapping
dan DefaultAnnotationHandlerMapping
(yang serupa RequestMappingHandlerMapping
tetapi tidak digunakan lagi).
Debugging
MVC Spring akan mencatat penangan yang terdaftar melalui RequestMappingHandlerMapping
. Misalnya, @Controller
suka
@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 @RequestMapping
harus cocok untuk Spring MVC untuk memilih penangan.
HandlerMapping
Implementasi 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 ApplicationContext
konfigurasi Anda .
Kesalahan umum lainnya
A DispatcherServlet
hanyalah Java EE tipikal Servlet
. Anda mendaftar dengan khas <web.xml>
<servlet-class>
dan <servlet-mapping>
deklarasi, atau langsung melalui ServletContext#addServlet
dalam 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 DispatcherServlet
dengan 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
, DisaptcherServlet
akan melaporkan
Tidak ada pemetaan yang ditemukan untuk permintaan HTTP dengan URI [/Example/WEB-INF/jsps/example-view-name.jsp]
diDispatcherServlet
dengan nama 'operator'
Karena DispatcherServlet
dipetakan ke /*
dan /*
cocok dengan semuanya (kecuali kecocokan persis, yang memiliki prioritas lebih tinggi), DispatcherServlet
akan dipilih untuk menangani forward
dari JstlView
(dikembalikan oleh InternalResourceViewResolver
). Di hampir setiap kasus, DispatcherServlet
tidak akan dikonfigurasi untuk menangani permintaan seperti itu .
Sebaliknya, dalam kasus sederhana ini, Anda harus mendaftarkan DispatcherServlet
ke /
, 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.