Ini adalah proyek yang dibuat sebagai bagian dari kursus yang saya ambil di University of Warsawa. Ini adalah implementasi sederhana dari wadah servlet yang mendukung Java Servlets yang sesuai dengan Java Servlet API. Meskipun cukup barebone, ia dapat memuat dan menjalankan aplikasi sederhana yang menggunakan fungsi dasar servlet termasuk pengiriman, JSP dan servlet async.
Saya tidak menemukan banyak implementasi kecil lain dari wadah servlet jadi jangan ragu untuk menggunakan ini sebagai contoh cara membuat wadah seperti ini. Perlu diingat bahwa karena pembatasan waktu, itu adalah proyek kereta yang sangat tidak sempurna dan sementara saya mencoba untuk tetap setia kepada Servlet API, saya mengambil beberapa kebebasan di sana -sini.
Idenya adalah bahwa wadah ini bekerja dengan cara yang sama seperti Tomcat. Anda dapat menambahkan kelas servlet menggunakan servletContainer :: addroute tetapi cara yang disukai adalah dengan menggunakan fungsi pemindaian komponen. Itu adalah jika aplikasi di -ritsleting ke file warName.war dan ditempatkan di direktori deploy di dalam server/src/main/resources itu akan dimuat pada start server dan tersedia di bawah localhost:8000/warName .
Secara default, server berjalan pada port 8000. Ini dapat diubah dalam fungsi Main . Fungsi ini juga berisi dan contoh cara memulai dan mengonfigurasi server ini.
Proyek ini dibangun menggunakan Gradle. Ini berisi dua Subproyasi: Aplikasi Server dan Demo (Database Buku Sederhana). Itu diuji di bawah Linux dan saya tidak tahu apakah itu berfungsi di bawah Windows/MacOS.
Untuk menjalankan penggunaan server:
./gradlew server:run
Mulai server mengharuskan kami untuk membuat instance dari ServletContainer .
ServletContainer(int threads) Membuat instance baru dari ServletContainer . dengan jumlah utas yang digunakan untuk membuat threadpool. Kolam ini akan digunakan untuk menangani permintaan HTTP.
void ServletContainer::start(int port) Mulai wadah servlet pada port yang diberikan. Perlu diingat bahwa file. WAR tidak dimuat pada saat ini. Mereka hanya dimuat ketika ServletContainer:servletScan dipanggil.
void ServletContainer::stop()Dengan anggun menghentikan wadah.
void ServletContainer::servletScan() Memuat semua file .War dari deploy Directory di dalam server/src/main/resources . Ini akan memuat file .jsp juga dan segera mentranspile mereka ke file .class. Hanya kelas yang dijelaskan dengan @WebServlet yang akan dimuat. Satu peringatan adalah bahwa file .war yang saya gunakan memiliki struktur direktori tertentu yang saya tidak yakin sama seperti pada kebanyakan file .war lainnya. Anda dapat memeriksa tugas lulusan war dalam aplikasi demo untuk melihat seperti apa struktur ini. Metode ini harus dipanggil paling banyak sekali sebelum metode mulai ().
void ServletContainer::servletScan(String url) Sama seperti ServletContainer::servletScan() tetapi dapat memuat file. WAR dari URL yang diberikan.
void ServletContainer::addRoute(Class<? extends HttpServlet> cls, String path)Menambahkan servlet ke wadah. Servlet hanya akan menangani URL yang diberikan (lihat FAQ untuk detail lebih lanjut).
Server mendukung penanganan bersamaan dari banyak klien sekaligus. Setiap klien akan ditangani oleh utas terpisah dari ThreadPool. Ukuran biliar default adalah 4 dan dapat diubah dalam fungsi Main .
Server akan mendukung kelas apa pun yang mewarisi dari httpservlet. Kelas seperti itu dapat ditambahkan menggunakan ServletContainer::addRoute .
Fungsi paling penting dari kelas -kelas ini diimplementasikan. Anda dapat menulis kepada klien menggunakan (hanya) PrintWriter , mengatur header dan status respons. HttpservletRequest dapat mengekstraksi URL permintaan, metode HTTP (GET, POST, DELETE, PATCH), parameter kueri dan parameter dari tubuh (dalam kasus pos). Data dikirim ke klien setelah menyiram buffer atau menutup HttpServletResponse . Menggunakan RequestDispatcher , Anda dapat mengirim permintaan ke servlet lain termasuk servlet JSP.
Ada dukungan untuk servlet async. Setelah HttpServletRequest::startAsync dieksekusi, permintaan tersebut masuk ke mode asinkron. Ada dua cara untuk menggunakan mode ini. Kode apa pun akan berjalan selama AsyncContext::complete dieksekusi di beberapa titik, yang mengakhiri koneksi ke klien. Anda juga dapat menggunakan AsyncConext::start(Runnable) , di sini Anda juga perlu mengeksekusi AsyncContext::complete di beberapa titik. Yang terakhir ini kompatibel dengan Java Servlet API. Ini juga mendukung batas waktu ( AsyncContext::setTimeout ) dan AsyncListener . Async Servlets diimplementasikan menggunakan CompletableFuture sehingga mereka akan menggunakan Threadpool terpisah dari yang digunakan untuk klien sinkron.
Jika aplikasi telah di -retas ke .War dan dipindahkan ke folder deploy , itu akan dimuat secara otomatis. Semua kelas dijelaskan dengan @WebServlet dan warisan dari HttpServlet akan ditambahkan ke wadah servlet dan akan tersedia di localhost:port/warName/servletUrl . Setiap kelas tersebut harus memiliki tepat satu servletUrl yang ditentukan dalam anotasi @WebServlet di atribut nilai. Jika aplikasi menggunakan JSP itu akan secara otomatis dikompilasi ke dalam .class dan dimuat. Banyak aplikasi yang dapat dimuat, namun, saya tidak tahu apa yang terjadi ketika ada nama kelas yang sama yang digunakan dalam dua aplikasi.
Server dapat mentranspile file .jsp ke .class. Ada dukungan untuk hampir semua sintaks di JSP. Itu termasuk:
<%@ page import/include=... %><% ... %><%! ... %><%= ... %><%-- %>${...} ${} Sintaks sebagian mendukung bahasa ekspresi. Operasi aritmatika sederhana dapat dilakukan, dan setiap ekspresi dari instance instance.property1.property2 akan dikonversi ke request.getAttribute("instance").getProperty1().getProperty2() . Di <% ... %> ada juga out.println(...) yang menulis langsung ke klien. JSP dapat ditampilkan menggunakan RequestDispatcher::forward atau tersedia langsung di localhost:8000/warName/jspFileName.jsp . Contoh tindakan JSP tersedia di localhost:8000/library/jsp . Perlu diingat bahwa saya menerapkan parsing diri saya sendiri sehingga format kode/sintaks dapat memecahkannya.
Untuk mendemonstrasikan Container Servlet, saya mengimplementasikan aplikasi sederhana yang mensimulasikan database buku. Buku dapat ditambahkan, dihapus dan diperbarui menggunakan formulir HTML. Semua buku juga dapat dilihat di tabel HTML. Frontend sepenuhnya dikembangkan menggunakan JSP. Aplikasi ini diseret ke dalam pustaka. Menggunakan tugas lulusan war , dipindahkan untuk deploy dan dimuat ke server saat dimulai.
Titik akhir:
Ada lebih dari 30 tes untuk memeriksa sebagian besar fungsi dan aplikasi demo. Lebih disukai untuk menjalankannya dari IntelliJ karena masalah yang dijelaskan dalam FAQ . Atau, mereka dapat dijalankan menggunakan:
./gradlew test
Proyek ini adalah bagian dari kursus universitas dan saya tidak diizinkan menggunakan perpustakaan pihak ketiga kecuali untuk JUnit.
Ada masalah dengan port soket sudah digunakan. Saya tidak pernah turun untuk memperbaikinya tetapi sebagian besar waktu itu bekerja ketika dijalankan dari IntelliJ.
Saat ini resolusi yang harus menangani URL yang diberikan cukup primitif. Pada dasarnya server url yang diberikan mencari servlet yang servletUrl adalah awalan url . Jika ada banyak yang dengan awalan terpanjang dipilih. Ini berarti bahwa jika servlet memiliki servletUrl sama dengan /app/home juga akan menangani /app/home/nonexisting/ , /app/home/12345 dll.
Siapa pun dipersilakan untuk berkontribusi pada proyek ini. Saya membuat beberapa masalah edisi pertama, jadi jangan ragu untuk memeriksanya :)