1. Pengantar Servlet
Servlet adalah teknologi yang disediakan oleh Sun Company untuk mengembangkan sumber daya web yang dinamis.
Sun menyediakan antarmuka servlet di API -nya. Jika pengguna ingin mengirim sumber daya web yang dinamis (yaitu, kembangkan program Java untuk mengeluarkan data ke browser), mereka perlu menyelesaikan dua langkah berikut:
1. Tulis kelas Java untuk mengimplementasikan antarmuka servlet.
2. Menyebarkan kelas Java yang dikembangkan ke server web.
Menurut kebiasaan nama konvensional, kami biasanya memanggil program Java yang mengimplementasikan Servlet Interface Servlet.
2. Proses Operasi Servlet
Program Servlet dipanggil oleh server web. Setelah server web menerima permintaan akses servlet klien:
① Server web pertama -tama memeriksa apakah telah dimuat dan membuat objek instance dari servlet. Jika demikian, maka jalankan langkah 4 secara langsung; Jika tidak, jalankan langkah 2.
② Muat dan buat objek instance dari servlet.
③Call Metode init () dari objek instance servlet.
④ Buat objek HTTPServletRequest untuk merangkum pesan permintaan HTTP dan objek HTTPSerVletResponse yang mewakili pesan respons HTTP, dan kemudian hubungi metode layanan servlet () dan lulus objek permintaan dan respons sebagai parameter.
⑤ Sebelum aplikasi Web dihentikan atau restart, mesin servlet akan menghapus instalasi servlet dan memanggil metode destroy () dari servlet sebelum menghapus instalasi.
3. Diagram panggilan servlet
4. Kembangkan servlet dalam gerhana
Buat proyek web baru di Eclipse, dan Eclipse akan secara otomatis membuat struktur direktori yang ditunjukkan pada gambar di bawah ini:
4.1. Kelas Implementasi Antarmuka Servlet
Servlet Interface Sun Company mendefinisikan dua kelas implementasi default, yaitu: GenericServlet dan httpservlet.
Httpservlet mengacu pada servlet yang dapat menangani permintaan HTTP. Ini menambahkan beberapa metode pemrosesan protokol HTTP ke antarmuka servlet asli, yang lebih kuat dari antarmuka servlet. Oleh karena itu, ketika menulis servlet, pengembang biasanya harus mewarisi kelas ini dan menghindari secara langsung mengimplementasikan antarmuka servlet.
Ketika httpservlet mengimplementasikan antarmuka servlet, itu menimpa metode layanan. Kode dalam Badan Metode akan secara otomatis menentukan metode permintaan pengguna. Jika itu adalah permintaan GET, metode doget dari httpservlet dipanggil. Jika itu adalah permintaan pos, metode dopost akan dipanggil. Oleh karena itu, saat menulis servlet, pengembang biasanya hanya perlu menimpa metode doget atau dopost alih -alih menimpa metode layanan.
4.2. Membuat dan menulis servlet melalui gerhana
Pilih paket GACL.Servlet.Study, klik kanan → baru → Servlet, seperti yang ditunjukkan pada gambar di bawah ini:
Dengan cara ini, kami akan menggunakan Eclipse untuk membantu kami membuat servlet dengan nama ServletDemo1. Akan ada kode berikut dalam servletDemo01 yang dibuat:
Paket gacl.servlet.study; import java.io.ioException; impor java.io.printwriter; impor javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.http.httpservlet; javax.servlet.http.httpservletResponse; kelas publik servletDemo1 memperluas httpservlet { /*** Metode doget dari servlet. <br> * * Metode ini dipanggil ketika suatu formulir memiliki metode nilai tag sama untuk mendapatkannya. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType ("Teks/html"); Printwriter out = response.getWriter (); out.println ("<! Doctype html public/"-// w3c // dtd html 4.01 transisi // en/">"); out.println ("<head> <title> a servlet </iteme> </head>"); out.println ("<body>"); out.print ("Ini"); out.print (this.getClass ()); out.println (", menggunakan metode GET"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); } /*** Metode dopost dari servlet. <br> * * Metode ini dipanggil ketika suatu formulir memiliki metode nilai tag sama untuk memposting. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType ("Teks/html"); Printwriter out = response.getWriter (); out.println ("<! Doctype html public/"-// w3c // dtd html 4.01 transisi // en/">"); out.println ("<Html>"); out.println ("<head> <title> a servlet </iteme> </head>"); out.println ("<body>"); out.println ("<body>"); out.println ("ini"); out.print (this.getClass ()); out.println (", menggunakan metode pos"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); }}Kode-kode ini secara otomatis dihasilkan oleh Eclipse, dan ada dua pasang tag dalam file web.xml, <servlet> </servlet> dan <servlet-Mapping> </servlet-Mapping>. Dua pasang tag ini dikonfigurasi dengan ServletDemo1, seperti yang ditunjukkan pada gambar di bawah ini:
Kemudian kita dapat mengakses servlet servletDemo1 melalui browser, seperti yang ditunjukkan pada gambar di bawah ini:
5. Perhatikan detail dalam pengembangan servlet
5.1. Konfigurasi Pemetaan URL Akses Servlet
Karena klien mengakses sumber daya di server web melalui alamat URL, jika program Servlet ingin diakses oleh dunia luar, ia harus memetakan program Servlet ke alamat URL. Pekerjaan ini dilakukan di file web.xml menggunakan elemen <servlet> dan elemen <servlet-Mapping>.
Elemen <servlet> digunakan untuk mendaftarkan servlet. Ini berisi dua elemen anak utama: <servlet-name> dan <servlet-class>, yang digunakan untuk mengatur nama pendaftaran servlet dan nama kelas penuh dari servlet masing-masing.
Elemen <servlet-Mapping> digunakan untuk memetakan jalur akses eksternal ke servlet terdaftar. Ini berisi dua elemen anak: <servlet-name> dan <rerl-pola>, yang digunakan untuk menentukan nama pendaftaran servlet dan jalur akses eksternal servlet. Misalnya:
<servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletDemo1</servlet-name> <url-pattern>/servlet/ServletDemo1</url-pattern> </servlet-mapping> The same Servlet dapat dipetakan ke beberapa URL, yaitu nilai pengaturan dari elemen anak <servlet-name> dari beberapa elemen <servlet-Mapping> dapat menjadi nama pendaftaran dari servlet yang sama. Misalnya: <servlet> <servlet-name> servletdemo1 </servlet-name> <servlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <servlet-mapping> <servlet-Mapping> <servlet-name> </servlet-Mapping> <servlet-Mapping> <servlet-name> servletdemo1 </servlet-name> <ritl-pola> /1.htm </rerl-pattern> </servlet-mapping> <servlet-Mapping> <servlet-name> SERVLETDEMO1 </servlet-name> <rest-patping> /.jspspats <servlet-Mapping> <servlet-name> servletdemo1 </servlet-name> <ritl-pola> /3.php </rerl-pola> </servlet-Mapping> <servlet-Mapping> <servlet-papping> <servlet-name> SERVLETDEMO1 </Servlet-name> <rerst-pattern> /4.aspx </urlat
Melalui konfigurasi di atas, ketika kami ingin mengakses servlet dengan nama servletDemo1, kami dapat menggunakan alamat berikut untuk mengakses:
http: // localhost: 8080/javaweb_servlet_study_20140531/servlet/servletdemo1
http: // localhost: 8080/javaweb_servlet_study_20140531/1.htm
http: // localhost: 8080/javaweb_servlet_study_20140531/2.jsp
http: // localhost: 8080/javaweb_servlet_study_20140531/3.php
http: // localhost: 8080/javaweb_servlet_study_20140531/4.aspx
ServletDemo1 dipetakan ke beberapa URL.
5.2. Gunakan * Pemetaan Wildcard untuk URL Akses Servlet
Karakter wildcard*juga dapat digunakan dalam URL yang dipetakan oleh servlet, tetapi hanya ada dua format tetap: satu adalah "*. Ekstensi", dan yang lainnya adalah awal dengan garis miring ke depan (/) dan diakhiri dengan "/*". Misalnya:
<servlet> <servlet-name> servletdemo1 </servlet-name> <servlet-class> gacl.servlet.study.servletdemo1 </servlet-class> </servlet> <servlet-mapping> <servlet-name> servletdemo1 </servlet-name> <rerl-pattion>/</figher> </servlet--name> </Url-pattern>/</*</figher> </servlet-name> <ron-pattern>/</*</servlet-patl>
*Ini dapat cocok dengan karakter apa pun, sehingga Anda dapat menggunakan URL apa pun untuk mengakses servlet servletDemo1, seperti yang ditunjukkan pada gambar di bawah ini:
Untuk beberapa hubungan pemetaan di bawah ini:
Peta servlet1 ke /abc /*
Peta servlet2 ke /*
Servlet3 memetakan ke /ABC
Peta servlet4 ke *.do
pertanyaan:
Ketika URL permintaan adalah "/abc/a.html", "/abc/*" dan "/*" keduanya cocok, yang ditanggapi servlet terhadap mesin servlet akan memanggil servlet1.
Ketika URL permintaan adalah "/ABC", keduanya "/ABC/*" dan "/ABC" cocok, yang ditanggapi servlet terhadap mesin servlet akan memanggil servlet3.
Ketika URL permintaan adalah "/abc/a.do", keduanya "/ABC/*" dan "*.do" cocok, yang ditanggapi servlet terhadap mesin servlet akan memanggil servlet1.
Ketika URL permintaan adalah "/a.do", keduanya "/*" dan "*.do" cocok, yang ditanggapi servlet terhadap mesin servlet akan memanggil servlet2.
Ketika URL permintaan adalah "/xxx/yyy/a.do", keduanya "/*" dan "*.do" cocok, yang ditanggapi servlet terhadap mesin servlet akan memanggil servlet2.
Prinsip pencocokan adalah "siapa pun yang lebih mirip akan menemukan siapa pun yang terlihat lebih"
5.3. Perbedaan antara servlet dan kelas Java biasa
Servlet adalah kelas Java untuk dihubungi oleh program Java lainnya (Mesin Servlet). Itu tidak dapat berjalan secara mandiri, dan operasinya sepenuhnya dikontrol dan dijadwalkan oleh mesin servlet.
Untuk beberapa permintaan servlet dari klien, biasanya server hanya akan membuat objek instance servlet. Dengan kata lain, setelah objek instance servlet dibuat, ia akan berada dalam memori dan melayani permintaan lainnya. Objek instance servlet tidak akan dihancurkan sampai wadah web keluar.
Selama seluruh kehidupan servlet, metode init servlet hanya dipanggil sekali. Setiap permintaan akses ke servlet menyebabkan mesin servlet untuk memanggil metode layanan servlet sekali. Untuk setiap permintaan akses, mesin servlet akan membuat objek permintaan httpservletRequest baru dan objek respons httpservletResponse baru, dan kemudian meneruskan kedua objek ini sebagai parameter ke metode layanan () dari servlet yang disebutnya. Metode layanan kemudian memanggil metode Doxxx sesuai dengan metode permintaan.
Jika elemen <boad-on-startup> dikonfigurasi dalam elemen <servlet>, maka ketika aplikasi web dimulai, ia akan memuat dan membuat objek instance servlet dan panggil metode init () dari objek instance servlet.
Misalnya:
<servlet> <servlet-name> Invoker </servlet-name> <servlet-class> org.apache.catalina.servlets.invokerServlet </servlet-class> <Boad-on-startup> 1 </load-on-startup> </servlet>
Tujuan: Tulis initservlet untuk aplikasi web. Servlet ini dikonfigurasi untuk dimuat saat startup untuk membuat tabel dan data basis data yang diperlukan untuk seluruh aplikasi web.
5.4. Servlet default
Jika jalur pemetaan servlet hanya slash maju (/), maka servlet ini menjadi servlet default dari aplikasi web saat ini.
URL apa pun dari elemen pencocokan <servlet-Mapping> yang tidak dapat ditemukan di file web.xml, permintaan akses mereka akan diserahkan ke servlet default untuk diproses, yaitu, servlet default digunakan untuk menangani permintaan akses yang tidak diproses oleh servlet lainnya. Misalnya:
<servlet> <servlet-name> servletdemo2 </servlet-name> <servlet-class> gacl.servlet.study.servletdemo2 </servlet-class> <bo load-on-startup> 1 </load-on-startup> <! <servlet-name> servletDemo2 </servlet-name> <rerl-pola>/</ruRl-pattern> </servlet-mapping>
Saat mengakses servlet yang tidak ada, servlet default yang dikonfigurasi digunakan untuk diproses, seperti yang ditunjukkan pada gambar di bawah ini:
Dalam file <TomCat Instalation Directory> /conf/web.xml, servlet bernama org.apache.catalina.servlets.defaultservlet terdaftar, dan servlet ini ditetapkan sebagai servlet default.
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <Param-Value> false </param-value> </it-param> <Boad-N-startup> 1 </boad-on-startup> </servlet> <!-Pemetaan untuk servlet default-> <servlet-Mapping> <servlet-name> default </servlet-name> <rerl-Pattern>/</url-Pattern> </servlet-mapter> <riglet> <rerl-pattern>/</url-pola> </servlet> </Servlet-Mapping> <rerl-Pattern>/</Url-Pattern> </Servlet>
Saat mengakses file dan gambar HTML statis di server Tomcat, Anda sebenarnya mengakses servlet default ini.
5.5. Masalah Keselamatan Thread Servlet
Ketika banyak klien mengakses servlet yang sama secara bersamaan, server web akan membuat utas untuk permintaan akses setiap klien dan memanggil metode layanan Servlet di utas ini. Oleh karena itu, jika sumber daya yang sama diakses dalam metode layanan, itu dapat menyebabkan masalah keamanan utas. Misalnya, kode berikut:
Kode yang tidak memiliki masalah keamanan utas:
Paket gacl.servlet.study; import java.io.ioException; import javax.servlet.servletException; import javax.servlet.htpservletrequest; impor javax.servlet.htp.htpservletreest; impor javax.servlet javax.servlet.http.httpservletResponse; kelas publik servletDemo3 memperluas httpservlet {public void doGet (httpservletRequest Request, httpservletResponse respons) Variabel I diakses secara bersamaan oleh banyak utas, tetapi tidak ada masalah keamanan utas, karena saya adalah variabel lokal dalam metode doGet. * Ketika beberapa utas mengakses metode doget secara bersamaan, setiap utas memiliki variabel i sendiri, * setiap utas mengoperasikan variabel I-nya sendiri, jadi tidak ada masalah keamanan utas * ketika multi-thread mengakses metode tertentu secara bersamaan, jika beberapa sumber daya (variabel, koleksi, dll.) Didefinisikan di dalam metode * maka setiap utas memiliki hal-hal ini, sehingga tidak ada masalah keamanan utas */ int i = di dalam metode ini * maka setiap utas memiliki hal-hal ini, sehingga tidak ada masalah keamanan utas *// int i = di dalam metode ini * maka setiap utas memiliki hal-hal ini, sehingga tidak ada masalah keamanan utas */ int i = i ++; response.getWriter (). Tulis (i); } public void dopost (permintaan httpservletRequest, respons httpservletResponse) melempar servletException, ioException {doGet (permintaan, respons); }} Kode dengan masalah keamanan utas:
Paket gacl.servlet.study; import java.io.ioException; impor javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.htp.htpservletreest; impor javax.servlet ServletDemo3 memperluas httpservlet {int i = 1; public void doGet (permintaan httpservletRequest, respons httpservletResponse) melempar servletException, ioException {i ++; coba {thread.sleep (1000*4); } catch (InterruptedException e) {E.PrintStackTrace (); } response.getWriter (). tulis (i+""); } public void dopost (permintaan httpservletRequest, respons httpservletResponse) melempar servletException, ioException {doGet (permintaan, respons); }}Tentukan saya sebagai variabel global. Ketika beberapa utas variabel akses saya bersamaan, akan ada masalah keamanan utas, seperti yang ditunjukkan pada gambar di bawah ini: Nyalakan dua browser pada saat yang sama untuk mensimulasikan akses bersamaan ke servlet yang sama. Biasanya, browser pertama harus melihat 2, dan browser kedua harus melihat 3, tetapi kedua browser melihat 3, yang tidak normal.
Masalah keamanan utas hanya ada ketika banyak utas mengoperasikan sumber daya yang sama secara bersamaan. Oleh karena itu, ketika menulis servlet, jika sumber daya tertentu (variabel, pengumpulan, dll.) Diakses secara bersamaan, akan ada masalah keselamatan utas. Jadi bagaimana cara menyelesaikan masalah ini?
Mari kita lihat kode berikut:
Paket gacl.servlet.study; import java.io.ioException; impor javax.servlet.servletException; import javax.servlet.http.httpservlet; import javax.servlet.htp.htpservletreest; impor javax.servlet ServletDemo3 memperluas httpservlet {int i = 1; public void doGet (permintaan httpservletRequest, respons httpservletResponse) melempar servletException, ioException { /*** Setelah disinkronkan ditambahkan, tidak ada masalah keamanan utas ketika akses bersamaan ke i. * Mengapa tidak ada masalah keamanan utas setelah disinkronkan ditambahkan? * Jika ada utas yang mengakses objek servlet sekarang, pertama -tama akan mendapatkan kunci objek servlet* Setelah dieksekusi, itu akan mengembalikan kunci ke objek servlet. Karena pertama kali mendapatkan kunci objek servlet, * Jadi ketika utas lain mengakses objek servlet, karena kunci telah diambil oleh utas sebelumnya, utas berikutnya hanya dapat menunggu dalam baris * */disinkronkan (ini) {// Di Java, setiap objek memiliki kunci, dan ini di sini merujuk pada objek servlet i ++; coba {thread.sleep (1000*4); } catch (InterruptedException e) {E.PrintStackTrace (); } response.getWriter (). tulis (i+""); }} public void dopost (permintaan httpservletRequest, respons httpservletResponse) melempar servletException, ioException {doGet (permintaan, respons); }}Sekarang pendekatan ini adalah menambahkan kunci ke objek servlet, memastikan bahwa hanya satu utas yang mengakses sumber daya dalam objek servlet kapan saja, sehingga tidak akan ada masalah keamanan utas, seperti yang ditunjukkan pada gambar di bawah ini:
Meskipun pendekatan ini memecahkan masalah keamanan utas, menulis servlet tidak boleh menangani masalah keamanan utas dengan cara ini. Jika 9999 orang mengakses servlet secara bersamaan, maka 9999 orang ini harus mengantri untuk mengakses secara berurutan.
Menanggapi masalah keamanan utas dari servlets, Sun memberikan solusi: Biarkan servlet menerapkan antarmuka singlethreadmodel. Jika servlet mengimplementasikan antarmuka singlethreadmodel, mesin servlet akan memanggil metode layanannya dalam mode utas tunggal.
Melihat API Sevlet, Anda dapat melihat bahwa antarmuka singlethreadmodel tidak menentukan metode atau konstanta apa pun. Di Java, antarmuka yang tidak menentukan metode atau konstanta disebut antarmuka tag. Salah satu antarmuka tag paling khas yang sering Anda lihat adalah "Serializable". Antarmuka ini juga tidak mendefinisikan metode atau konstanta apa pun. Apa gunanya antarmuka tag di java? Fungsi utama adalah menandai suatu objek dan memberi tahu JVM apa yang dapat dilakukan objek ini. Misalnya, objek kelas yang mengimplementasikan antarmuka "serializable" dapat diserialisasi, dan ada juga antarmuka "dapat dikloning", yang juga merupakan antarmuka tag. Secara default, benda -benda di Java tidak diizinkan untuk dikloning, seperti orang -orang dalam kehidupan nyata, kloning tidak diperbolehkan, tetapi selama antarmuka "yang dapat dikloning" diimplementasikan, objek tersebut dapat dikloning.
Biarkan Servlet mengimplementasikan antarmuka singlethreadmodel, cukup tambahkan deklarasi untuk mengimplementasikan antarmuka singlethreadmodel ke definisi kelas servlet.
Untuk servlet yang mengimplementasikan antarmuka singlethreadmodel, mesin servlet masih mendukung akses bersamaan multi-utara ke servlet. Metode ini adalah untuk menghasilkan beberapa objek instan servlet, dan setiap utas bersamaan memanggil objek instance servlet independen secara terpisah.
Menerapkan antarmuka singlethreadmodel tidak dapat benar-benar menyelesaikan masalah keamanan utas dari servlets, karena mesin servlet akan membuat beberapa objek instance servlet, dan benar-benar memecahkan masalah keamanan multi-thread mengacu pada masalah bahwa objek instance servlet dipanggil oleh banyak utas pada waktu yang sama. Faktanya, di Servlet API 2.4, singlethreadmodel telah ditandai sebagai sudah usang (ketinggalan zaman).
Di atas adalah semua tentang artikel ini, saya harap ini akan membantu untuk pembelajaran semua orang.