Perbedaan antara / dan / * dalam pola url pemetaan servlet

175

Kode yang dikenal:

<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    <servlet-name>main</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

Pemahaman saya adalah bahwa /*peta untuk http://host:port/context/*.

Bagaimana dengan /? Itu pasti tidak memetakan untuk http://host:port/contextroot saja. Bahkan, ia akan menerima http://host:port/context/hello, tetapi menolak http://host:port/context/hello.jsp.

Adakah yang bisa menjelaskan bagaimana http://host:port/context/hellodipetakan?

Candy Chiu
sumber

Jawaban:

268

<url-pattern>/*</url-pattern>

Pada /*servlet menimpa semua servlet lain, termasuk semua servlet yang disediakan oleh servletcontainer seperti servlet default dan servlet JSP. Apapun permintaan Anda, itu akan berakhir di servlet itu. Dengan demikian, ini adalah pola URL yang buruk untuk servlets. Biasanya, Anda ingin menggunakan /*pada Filtersaja. Ia dapat membiarkan permintaan melanjutkan ke servlet mana pun yang mendengarkan pada pola URL yang lebih spesifik dengan menelepon FilterChain#doFilter().

<url-pattern>/</url-pattern>

Tidak /mengesampingkan servlet lainnya. Itu hanya menggantikan servlet builtin default servlet untuk semua permintaan yang tidak cocok dengan servlet terdaftar lainnya. Ini biasanya hanya dipanggil pada sumber daya statis (CSS / JS / image / dll) dan daftar direktori. Server servlet bawaan bawaan ini juga mampu menangani permintaan cache HTTP, streaming media (audio / video) dan resume unduhan file. Biasanya, Anda tidak ingin mengganti servlet default karena Anda harus mengurus semua tugasnya, yang tidak sepele (pustaka utilitas JSF OmniFaces memiliki contoh sumber terbuka ). Ini juga merupakan pola URL yang buruk untuk servlets. Mengenai mengapa halaman JSP tidak mengenai servlet ini, itu karena servletcontainer yang dibangun di dalam JSP servlet akan dipanggil, yang secara default sudah dipetakan pada pola URL yang lebih spesifik *.jsp.

<url-pattern></url-pattern>

Lalu ada juga pola URL string kosong . Ini akan dipanggil ketika root konteks diminta. Ini berbeda dari <welcome-file>pendekatan yang tidak dipanggil ketika ada subfolder yang diminta. Ini kemungkinan besar pola URL yang sebenarnya Anda cari seandainya Anda menginginkan " halaman beranda servlet ". Saya hanya harus mengakui bahwa saya secara intuitif mengharapkan pola URL string kosong dan pola slash URL /didefinisikan secara persis sebaliknya, jadi saya dapat memahami bahwa banyak pemula yang bingung mengenai hal ini. Tapi memang begitu.

Pengontrol Depan

Dalam kasus Anda benar-benar berniat untuk memiliki front controller servlet, maka Anda akan lebih terbaik peta itu pada pola URL yang lebih spesifik seperti *.html, *.do, /pages/*, /app/*, dll Anda dapat menyembunyikan diri pola URL front controller dan penutup sumber daya statis pada pola URL umum seperti /resources/*,, /static/*dll dengan bantuan filter servlet. Lihat juga Cara mencegah sumber daya statis ditangani oleh servlet pengontrol depan yang dipetakan pada / * . Perlu dicatat bahwa Spring MVC memiliki servlet sumber daya statis bawaan, jadi itu sebabnya Anda bisa memetakan pengontrol depannya /jika Anda mengonfigurasi pola URL umum untuk sumber daya statis di Spring. Lihat juga Bagaimana menangani konten statis di Spring MVC?

BalusC
sumber
9
Terima kasih. Setelah beberapa penelitian, saya ingin mengklarifikasi hal yang halus. / menimpa servlet default yang dipasang oleh server web. Misalnya, Tomcat menginstal DefaultServlet yang menyajikan sumber daya statis. Menggunakan / menghilangkan servlet default sebagai efek samping (kemungkinan besar tidak diinginkan).
Candy Chiu
Yah, saya tidak akan menyebutnya "menimpa", tetapi "mengganti". Dapat bermanfaat untuk mengganti servlet default seperti itu.
BalusC
1
<url-pattern> </url-pattern> melempar kesalahan: <url-pattern> tidak valid dalam pemetaan servlet
slim
Pesan kesalahan berasal dari kucing jantan, bukan IDE saya; Namun, saya menggunakan Tomcat 6, jadi itu mungkin masalahnya;)
slim
2
@ BalusC, bisakah Anda memberi tahu saya apa /**yang ditunjukkan oleh pola?
Sajib Acharya
45

Saya ingin menambahkan jawaban BalusC dengan aturan pemetaan dan contoh.

Aturan pemetaan dari spesifikasi Servlet 2.5:

  1. Peta URL yang tepat
  2. Memetakan jalur wildcard
  3. Ekstensi peta
  4. Peta ke servlet default

Dalam contoh kita, ada tiga servlet. / adalah servlet default yang dipasang oleh kami. Tomcat menginstal dua servlet untuk melayani jsp dan jspx. Jadi untuk memetakanhttp://host:port/context/hello

  1. Tidak ada servlet URL yang diinstal, selanjutnya.
  2. Tidak ada servlets jalur lintasan diinstal, selanjutnya.
  3. Tidak cocok dengan ekstensi apa pun, selanjutnya.
  4. Peta ke servlet default, kembali.

Untuk memetakan http://host:port/context/hello.jsp

  1. Tidak ada servlet URL yang diinstal, selanjutnya.
  2. Tidak ada servlets jalur lintasan diinstal, selanjutnya.
  3. Ditemukan servlet ekstensi, kembali.
Candy Chiu
sumber
25

Mungkin Anda perlu tahu bagaimana url dipetakan juga, karena saya menderita 404selama berjam-jam. Ada dua jenis penangan yang menangani permintaan. BeanNameUrlHandlerMappingdan SimpleUrlHandlerMapping. Ketika kami mendefinisikan servlet-mapping, kami menggunakan SimpleUrlHandlerMapping. Satu hal yang perlu kita ketahui adalah kedua penangan ini berbagi properti umum yang disebut sebagai alwaysUseFullPathdefault false.

falsedi sini berarti Spring tidak akan menggunakan path lengkap untuk memetakan url ke controller. Apa artinya? Itu berarti ketika Anda mendefinisikan servlet-mapping:

<servlet-mapping>
    <servlet-name>viewServlet</servlet-name>
    <url-pattern>/perfix/*</url-pattern>
</servlet-mapping>

pawang akan benar-benar menggunakan *bagian tersebut untuk menemukan pengontrol. Misalnya, pengontrol berikut akan menghadapi 404kesalahan saat Anda memintanya menggunakan/perfix/api/feature/doSomething

@Controller()
@RequestMapping("/perfix/api/feature")
public class MyController {
    @RequestMapping(value = "/doSomething", method = RequestMethod.GET) 
    @ResponseBody
    public String doSomething(HttpServletRequest request) {
        ....
    }
}

Ini pasangan yang sempurna, bukan? Tapi kenapa 404. Seperti disebutkan sebelumnya, nilai default alwaysUseFullPathadalah salah, yang berarti dalam permintaan Anda, hanya /api/feature/doSomethingdigunakan untuk menemukan Controller yang sesuai, tetapi tidak ada Controller yang peduli tentang jalur itu. Anda perlu mengubah url /perfix/perfix/api/feature/doSomethingatau menghapus perfixdari pangkalan MyController @RequestingMapping.

hakunami
sumber
8

Saya pikir jawaban Candy sebagian besar benar. Ada satu bagian kecil yang saya pikir sebaliknya.

Untuk memetakan host: port / context / hello.jsp

  1. Tidak ada servlet URL yang diinstal, selanjutnya.
  2. Ditemukan wildcard paths servlets , kembali.

Saya percaya bahwa mengapa "/ *" tidak cocok dengan host: port / konteks / halo karena ia memperlakukan "/ halo" sebagai jalur alih-alih file (karena tidak memiliki ekstensi).

hehe
sumber
2

Perbedaan mendasar antara /*dan /adalah bahwa servlet dengan pemetaan /*akan dipilih sebelum servlet dengan pemetaan ekstensi (seperti *.html), sedangkan servlet dengan pemetaan /akan dipilih hanya setelah pemetaan ekstensi dipertimbangkan (dan akan digunakan untuk permintaan apa pun yang tidak t cocok dengan yang lain --- itu adalah "servlet default").

Secara khusus, /*pemetaan akan selalu dipilih sebelum /pemetaan. Memiliki salah satu mencegah permintaan dari mencapai servlet default wadah sendiri.

Entah akan dipilih hanya setelah pemetaan servlet yang sama persis (seperti /foo/bar) dan mereka yang pemetaan jalan lebih lama dari /*(suka /foo/*). Perhatikan bahwa pemetaan string kosong adalah pencocokan tepat untuk root konteks ( http://host:port/context/).

Lihat Bab 12 dari Spesifikasi Java Servlet, tersedia dalam versi 3.1 di http://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html .

Robert Tupelo-Schneck
sumber