JavaRush /Blog Java /Random-MS /Dari Hello World hingga Spring Web MVC dan apakah kaitan ...

Dari Hello World hingga Spring Web MVC dan apakah kaitan servlet dengannya

Diterbitkan dalam kumpulan
Dari Hello World ke Spring Web MVC dan apakah kaitan servlet dengannya - 1

pengenalan

Seperti yang kita ketahui, kejayaan Java datang dengan tepat berkat evolusi perisian yang berusaha untuk menyambung ke rangkaian. Oleh itu, kami akan mengambil aplikasi konsol biasa " Hello World " sebagai asas dan memahami apa yang diperlukan untuk menjadi aplikasi rangkaian daripada aplikasi konsol. Jadi, pertama anda perlu membuat projek Java. Pengaturcara adalah orang yang malas. Pada zaman prasejarah, apabila ada yang memburu mamut, yang lain duduk dan cuba untuk tidak keliru dalam pelbagai jenis perpustakaan dan struktur direktori Java. Supaya pembangun dapat mengawal proses mencipta aplikasi, supaya dia boleh menulis "Saya mahukan perpustakaan versi 2 ini dan itu", mereka datang dengan alat khas - membina sistem. Dua yang paling terkenal ialah Maven dan Gradle . Untuk artikel ini kami akan menggunakan Gradle. Jika sebelum ini kita perlu membuat struktur direktori sendiri, kini Gradle, menggunakan Gradle Init Plugin, membolehkan kita mencipta projek Java dengan struktur direktori dan kelas Utama asas dalam satu arahan: gradle init --type java-application Perintah ini melakukan pemula (init) untuk kami aplikasi Java (java-application ) dengan konsol Hello World. Selepas selesai, fail akan muncul dalam direktori - build.gradle . Ini ialah skrip binaan kami - iaitu skrip tertentu untuk mencipta aplikasi dengan penerangan tentang tindakan yang perlu dilakukan untuk ini. Mari bukanya dan tambah baris padanya: jar.baseName = 'webproject' Gradle membenarkan anda melakukan pelbagai tindakan pada projek dan tindakan ini dipanggil tugasan . Dengan melaksanakan perintah (tugas) fail JAR akan dibuat gradle builddalam direktori /build/libs . Dan, seperti yang anda sangka, namanya kini akan menjadi webproject.jar . Tetapi jika kita melaksanakan java -jar ./build/libs/webproject.jar, kita akan mendapat ralat: no main manifest attribute. Ini kerana untuk aplikasi java anda perlu melampirkan manifes - ini ialah penerangan tentang cara bekerja dengan aplikasi itu, cara melihatnya. Kemudian JVM, yang akan melaksanakan aplikasi java, akan mengetahui kelas mana yang menjadi titik masuk kepada program dan maklumat lain (contohnya, classpath). Jika kita melihat dengan lebih dekat kandungan skrip binaan, kita akan melihat pemalam disambungkan. Contohnya: apply plugin: 'java' Jika kita pergi ke halaman Gradle Java Plugin , kita dapat melihat bahawa kita boleh mengkonfigurasi manifes:
jar {
    manifest {
        attributes 'Main-Class': 'App'
    }
}
Kelas utama, titik masuk kepada program, telah dihasilkan untuk kami oleh Gradle Init Plugin. Dan ia juga dinyatakan dalam parameter mainClassName. Tetapi ini tidak sesuai dengan kami, kerana... tetapan ini merujuk kepada pemalam lain, Gradle Application Plugin . Jadi, kami mempunyai aplikasi Java yang memaparkan Hello World pada skrin. Aplikasi Java ini dibungkus dalam JAR (Java ARchive). Ia mudah, berasaskan konsol, tidak terkini. Bagaimana untuk mengubahnya menjadi aplikasi web?
От Hello World до Spring Web MVC и при чём тут сервлеты - 2

API Servlet

Agar Java dapat berfungsi dengan rangkaian, spesifikasi yang dipanggil Servlet API muncul kembali pada zaman dahulu . Spesifikasi inilah yang menerangkan interaksi pelanggan-pelayan, menerima mesej daripada klien (contohnya, penyemak imbas) dan menghantar respons (contohnya, dengan teks halaman). Sememangnya, banyak yang telah berubah sejak itu, tetapi maksudnya ialah agar aplikasi Java menjadi aplikasi web, API Servlet digunakan. Untuk tidak membuat spekulasi secara tidak berasas, mari kita ambil spesifikasi itu: JSR-000340 JavaTM Servlet 3.1 . Pertama sekali, kami berminat dengan " Bab 1: Gambaran Keseluruhan ". Ia menerangkan konsep asas yang mesti kita fahami. Pertama, apakah itu servlet? Bab " 1.1 Apakah Servlet? " mengatakan bahawa Servlet ialah komponen Java yang diuruskan oleh bekas dan yang menjana kandungan dinamik. Seperti komponen Java yang lain, servlet ialah kelas Java yang disusun menjadi bytecode dan boleh dimuatkan ke dalam pelayan web menggunakan teknologi Java. Adalah penting bahawa servlet berinteraksi dengan klien web (contohnya, pelayar) dalam rangka kerja paradigma permintaan/tindak balas, yang dilaksanakan oleh Kontena Servlet. Ternyata Servlet tinggal dalam beberapa jenis Bekas Servlet. Apakah ini? Dalam bab " 1.2 Apakah itu Kontena Servlet? " dikatakan bahawa Kontena Servlet ialah sebahagian daripada pelayan web atau pelayan aplikasi yang menyediakan perkhidmatan rangkaian yang melaluinya permintaan dihantar dan respons dihantar. Bekas Servlet ini menguruskan kitaran hayat servlet. Semua Bekas Servlet dikehendaki menyokong protokol HTTP sekurang-kurangnya, tetapi mungkin menyokong yang lain. Contohnya, HTTPS. Adalah penting juga bahawa Kontena Servlet boleh mengenakan sebarang sekatan berkaitan keselamatan ke atas persekitaran di mana servlet dilaksanakan. Ia juga penting bahawa menurut " 10.6 Fail Arkib Aplikasi Web " aplikasi web mesti dibungkus dalam fail WAR (Arkib Web). Iaitu, sekarang kita perlu mengalih keluar balang dan pemalam aplikasi untuk sesuatu yang lain. Dan ini ialah pemalam Gradle WAR . Dan bukannya jar.baseName tentukan war.baseName Kerana Memandangkan kami tidak lagi menggunakan pemalam jar, kami juga telah mengalih keluar tetapan manifes. Apabila kami melancarkan JAR, Mesin Maya Java (JVM) perlu diberitahu melalui manifes cara bekerja dengan aplikasi kami. Kerana JVM menjalankannya. Aplikasi web, nampaknya, dilaksanakan oleh beberapa jenis pelayan web. Nampaknya dia perlu memberitahunya bagaimana untuk bekerja dengan aplikasi web kami? Dan ternyata ya. Aplikasi web mempunyai manifesto khas mereka sendiri. Ia dipanggil Deskriptor Deployment . Seluruh bahagian didedikasikan untuknya: “ 14. Deskriptor Deployment ”. Terdapat bahagian penting: " Bab 10:". Ia bercakap tentang aplikasi web dari sudut pandangan API Servlet. Contohnya, dalam bab " 10.5 Struktur Direktori " ia ditunjukkan di mana Deskriptor Deployment sepatutnya: /WEB-INF/web.xml. Di mana hendak meletakkan WEB-INF? Seperti yang dinyatakan dalam pemalam Gradle WAR , ia menambah susun atur baharu : src/main/webapp. Oleh itu, mari kita cipta direktori sedemikian, di dalamnya kita akan mencipta direktori WEB-INF, dan di dalamnya kita akan mencipta fail web.xml. Adalah penting bahawa direktori itu dipanggil WEB-INF, dan bukan META-INF! Mari salin daripada " 14.5.1 Contoh Asas " contoh XML:
От Hello World до Spring Web MVC и при чём тут сервлеты - 3
Seperti yang kita lihat, dokumen XML digunakan untuk konfigurasi. Dokumen XML, untuk dianggap sah (Sah), mesti mematuhi beberapa "skema". Anda boleh menganggap ini sebagai sejenis antara muka untuk dokumen XML. Skema menentukan elemen apa yang boleh ada dalam dokumen XML, jenis data yang boleh menentukan elemen, pesanan, keperluan dan aspek lain. Contoh yang disalin daripada dokumentasi menunjukkan versi 2.5, tetapi kami mahu menggunakan versi 3.1. Sememangnya, spesifikasi berubah apabila versi berubah, dan ciri baharu telah ditambah. Oleh itu, anda perlu menggunakan skema selain daripada yang digunakan untuk versi 2.5 (web-app_2_5.xsd). Skim apakah yang perlu saya gunakan untuk versi 3.1? Dokumentasi akan membantu kami dengan ini, bab " 14.3 Deployment Descriptor ", yang menyatakan specification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Iaitu, kita perlu menggantikan pautan ke skema dengan xsd yang ditentukan di mana-mana, tidak lupa menukarnya version="2.5"kepada 3.1, dan juga menukar ruang nama di mana-mana ( xmlns dan dalam xsi:schemaLocation). Mereka menunjukkan dalam ruang nama yang mana kami akan bekerja (secara ringkasnya, nama elemen apa yang boleh kami gunakan). Jika anda membuka fail skema, targetNamespace akan mengandungi ruang nama yang sama yang harus kami tentukan:
От Hello World до Spring Web MVC и при чём тут сервлеты - 4
Seperti yang kami ingat, dalam fail Manifest of the Jar kami menulis kelas mana yang kami mahu gunakan. Apa yang perlu dilakukan di sini? Di sini kita perlu menentukan kelas servlet yang ingin kita gunakan apabila kita menerima permintaan daripada klien web. Penerangan boleh dibaca dalam bab " 14.4 Diagram Deskriptor Deployment ". Ia akan kelihatan seperti ini:
От Hello World до Spring Web MVC и при чём тут сервлеты - 5
Semuanya mudah di sini. Serverlet diisytiharkan, dan kemudian ia dipetakan ke templat tertentu. Dalam kes ini, pada /app. Apabila templat dilaksanakan, kaedah servlet akan dilaksanakan. Untuk kecantikan, kelas App harus dipindahkan ke pakej, tidak lupa untuk membetulkan konfigurasi xml. Tetapi bukan itu sahaja. Apl mestilah servlet. Apakah maksud menjadi servlet? Ini bermakna kita mesti mewarisi daripada HttpServlet . Contohnya boleh dilihat dalam bab " 8.1.1 @WebServlet ". Menurutnya, kelas App kami akan kelihatan seperti ini:
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class App extends HttpServlet {
    public String getGreeting() {
        return "Hello world.";
    }

	public void doGet(HttpServletRequest request, HttpServletResponse response) {
		response.setContentType("text/html");
		try {
			response.getWriter().println(getGreeting());
		} catch (IOException e) {
			throw new IllegalStateException(e);
		}
	}
}
Tetapi projek kami belum siap lagi. Kerana kami kini bergantung pada Servlet API versi 3.1. Ini bermakna dalam skrip binaan kami, kami perlu menunjukkan pergantungan pada API Servlet. JVM perlu tahu bahawa apa yang anda tulis dalam kod adalah betul dan cara menggunakannya. Seperti yang kita ingat, spesifikasi pada asasnya hanyalah antara muka yang menerangkan bagaimana semuanya harus berfungsi. Dan pelaksanaannya terletak pada bahagian pelayan web. Oleh itu, tanpa API Servlet akan ada Cari perpustakaan yang diperlukan pada Maven Central: javax.servlet-api . Dan tambahkan entri pada blok dependencies . Dalam repositori Maven, seperti yang anda lihat, ia mengatakan disediakan. Sebelum menggunakan kebergantungan, anda mesti menentukan skop. Gradle tidak mempunyai skop bernama "disediakan", tetapi ia mempunyai skop " compile only ". Oleh itu, kami akan menunjukkan: providedCompile 'javax.servlet:javax.servlet-api:3.1.0' Ugh, semuanya nampaknya baik-baik saja? Gradle Build akan membina projek kami menjadi fail WAR. Dan apa yang perlu kita lakukan seterusnya dengannya? Pertama, kita memerlukan Pelayan Web. Di Google kami menulis " senarai java pelayan web " dan melihat senarai pelayan web. Mari pilih daripada senarai ini, contohnya, TomCat . Pergi ke tapak web Apache Tomcat , muat turun versi terkini (kini versi 9) sebagai arkib zip (jika untuk Windows). Buka bungkusannya ke dalam beberapa direktori. Hore, kami mempunyai pelayan web. Daripada direktori pelayan web dalam subdirektori bin , kami melaksanakan catalina dari baris arahan dan melihat pilihan yang tersedia. Jom buat: catalina start. Setiap pelayan web mempunyai direktori yang dipantau oleh pelayan web. Jika fail aplikasi web muncul di sana, pelayan web mula memasangnya. Pemasangan ini dipanggil deployment atau deployment . Ya ya, itulah sebabnya " deskriptor penempatan ". Iaitu, cara menggunakan aplikasi dengan betul. Dalam Tomcat direktori ini ialah webapps . Mari salin perang yang kami buat menggunakan gradle build di sana. Selepas ini, dalam log kita akan melihat sesuatu seperti: Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [время] ms Untuk memahami dengan lebih baik, dalam direktori tomcat kita akan mengedit fail \conf\tomcat-users.xml, menambah baris berikut:
От Hello World до Spring Web MVC и при чём тут сервлеты - 6
Sekarang kita mulakan semula pelayan (catalina stop, catalina start) dan pergi ke alamat. http://127.0.0.1:8080/manager Di sini kita akan melihat laluan semua aplikasi. Projek web kami kemungkinan besar diberi laluan /projek web. Apakah laluan ini? Spesifikasi dalam bab " 10.1 Aplikasi Web Dalam Pelayan Web " menyatakan bahawa aplikasi web dikaitkan dengan beberapa laluan dalam aplikasi (dalam kes ini, /webproject). Semua permintaan melalui laluan ini akan dikaitkan dengan ServletContext yang sama. Laluan ini juga dipanggil contextRoot . Dan menurut " 10.2 Hubungan dengan ServletContext " bekas servlet mengaitkan aplikasi web dan ServletContext satu dengan satu. Iaitu, setiap aplikasi web mempunyai ServletContext sendiri. Apakah ServletContext ? Seperti yang dinyatakan dalam spesifikasi, ServletContext ialah objek yang menyediakan servlet dengan "pandangan aplikasi " di mana ia dijalankan. Konteks Servlet diterangkan dengan lebih terperinci dalam Bab 4 spesifikasi API Servlet. Anehnya, Servlet API dalam versi 3.1 tidak lagi memerlukan web.xml untuk hadir. Sebagai contoh, anda boleh menentukan servlet menggunakan anotasi:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/app2")
public class App2 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");
        response.getWriter().println("app2");
    }
}
Juga disyorkan pada topik: " Temuduga EE Java - API Servlet JEE (Soalan dan Jawapan) ". Jadi, kami mempunyai Servlet - ia bertanggungjawab untuk respons yang perlu diberikan kepada pelanggan web. Kami mempunyai ServletContainer yang menerima permintaan daripada pengguna, sepadan dengan laluan yang telah diakses dengan laluan ke servlet, dan jika padanan ditemui, laksanakan Servlet. baik. Apakah tempat yang diduduki Spring dalam gambar dunia ini ?

MVC Web Musim Bunga

Hebat, kami mempunyai aplikasi web. Sekarang kita perlu menyambung Spring. Bagaimana kita boleh melakukan ini? Pertama, anda perlu memikirkan cara menyambung Spring dengan betul ke projek anda. Ternyata sebelum ini adalah mungkin untuk melakukan ini mengikut dokumentasi projek platform Spring , tetapi kini " Platform akan mencapai penghujung hayatnya yang disokong pada 9 April 2019 ", iaitu, tidak digalakkan untuk gunakannya, kerana tidak lama lagi ia tidak akan disokong lagi. Satu-satunya jalan keluar ialah " Pengguna Platform digalakkan untuk mula menggunakan pengurusan pergantungan Spring Boot ". Oleh itu, mari kita beralih kepada dokumentasi Spring Boot . Biar saya jelaskan bahawa kami tidak menggunakan Spring Boot itu sendiri, tetapi hanya Pengurusan Ketergantungan daripada Spring Boot. Iaitu, projek Spring Boot boleh memberikan pengetahuan tentang versi perpustakaan yang hendak digunakan (termasuk Spring MVC). Di sana kita akan dapati 3.2. Menggunakan pengurusan pergantungan Spring Boot secara berasingan . Menurut dokumentasi, tambahkan yang berikut pada skrip binaan:
plugins {
    id 'org.springframework.boot' version '2.0.4.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
Dan
dependencyManagement {
    imports {
        mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
    }
}
Seperti yang anda lihat, kami menunjukkan apply false, i.e. Kami tidak menggunakan Spring Boot itu sendiri, tetapi kami menggunakan pengurusan pergantungan dari sana. Pengurusan pergantungan ini juga dipanggil BOM - " Bill Of Materials ". Kini kami bersedia untuk menyambung projek Spring Web MVC itu sendiri. Spring Web MVC ialah sebahagian daripada projek Spring Framework dan kami berminat dengan bahagian " Web Servlet ". Mari tambahkan kebergantungan pada skrip binaan: compile 'org.springframework:spring-webmvc'. Seperti yang dapat kita lihat, kita menetapkan penyusunan skop, kerana pelayan web tidak memberikan kami Spring. Projek kami terpaksa memasukkan perpustakaan Spring di dalam dirinya sendiri. Seterusnya, adalah penting untuk kita membaca bahagian " 1.2. DispatcherServlet ", di mana dikatakan bahawa Spring MVC dibina di sekitar corak " Pengawal hadapan ", di mana terdapat beberapa jenis servlet pusat yang menyediakan konfigurasi dan delegasi kepada komponen lain. . Penghantar boleh diterjemahkan sebagai penghantar. Jadi, pertama sekali, dalam web.xml kami mengisytiharkan:
От Hello World до Spring Web MVC и при чём тут сервлеты - 7
Seperti yang kita lihat, ini sebenarnya Pendengar biasa yang ditakrifkan dalam spesifikasi API Servlet. Untuk menjadi lebih tepat, ini ialah ServletContextListener, iaitu, ia dicetuskan untuk memulakan Konteks Servlet untuk aplikasi web kami. Seterusnya, anda perlu menentukan tetapan yang akan memberitahu Spring di mana konfigurasi xml khasnya dengan tetapan terletak:
От Hello World до Spring Web MVC и при чём тут сервлеты - 8
Seperti yang anda lihat, ini hanyalah tetapan biasa yang disimpan pada tahap Konteks Servlet, tetapi yang akan digunakan oleh Spring apabila memulakan Konteks Aplikasi. Sekarang anda perlu mengisytiharkan, bukannya semua servlet, satu penghantar tunggal yang mengedarkan semua permintaan lain.
От Hello World до Spring Web MVC и при чём тут сервлеты - 9
Dan tiada keajaiban di sini. Jika kita lihat, ia adalah HttpServlet, di mana Spring melakukan banyak perkara yang menjadikannya rangka kerja. Yang tinggal hanyalah mengaitkan (memetakan) templat URL tertentu dengan servlet:
От Hello World до Spring Web MVC и при чём тут сервлеты - 10
Semuanya sama seperti yang kita lakukan sebelum ini. Sekarang mari kita cipta sesuatu yang harus dipaparkan oleh pelayan web kita. Sebagai contoh, mari buat subdirektori halaman dalam WEB-INF kami, dan akan ada fail hello.jsp. Kandungan boleh menjadi yang paling primitif. Sebagai contoh, di dalam tag html terdapat tag h1 dengan teks " Hello World ". Dan jangan lupa untuk mencipta fail applicationContext.xmlyang kami tentukan sebelum ini. Mari kita ambil contoh daripada dokumentasi Spring: " 1.10.3. Mengesan kelas secara automatik dan mendaftar definisi kacang ".
От Hello World до Spring Web MVC и при чём тут сервлеты - 11
Kerana kami mendayakan pengesanan automatik dengan cara ini, kami kini boleh membuat 2 kelas (mereka akan dianggap Spring Beans kerana penggunaan anotasi Spring khas), yang Spring kini akan mencipta sendiri dan menyesuaikan aplikasi kami dengan bantuan mereka:
  1. Konfigurasi web contohnya konfigurasi gaya Java:

    @Configuration
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void configureViewResolvers(ViewResolverRegistry registry) {
            registry.jsp("/WEB-INF/pages/", ".jsp");
        }
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    }

    Contoh ini diterangkan dalam dokumentasi Spring Framework: " 1.11. MVC Config ".

    Di sini kami mendaftarkan ViewResolver, yang akan membantu menentukan di mana halaman jsp berada. Kaedah kedua memastikan bahawa " Default servlet " didayakan.

    Anda boleh membaca lebih lanjut tentang ini di sini: " Apakah keperluan dan penggunaan default-servlet-handler ".

  2. Pengawal HelloController untuk menerangkan pemetaan permintaan kepada JSP tertentu

    @Controller
    public class HelloController {
        @GetMapping("/hello")
        public String handle(Model model) {
            return "hello";
        }
    }

    Di sini kami telah menggunakan anotasi @Controller yang diterangkan dalam dokumentasi dalam bab " 1.4. Pengawal Beranotasi ".

Sekarang, apabila aplikasi kami digunakan, apabila kami menghantar permintaan /webproject/hello(di mana /webproject ialah akar konteks), DispatcherServlet akan diproses terlebih dahulu. Beliau, sebagai penghantar utama, akan menentukan bahawa kami /* sepadan dengan permintaan semasa, yang bermaksud bahawa DispatcherServlet mesti melakukan sesuatu. Kemudian ia akan melalui semua pemetaan yang ditemuinya. Ia akan melihat bahawa terdapat HelloController dengan kaedah pemegang yang dipetakan ke /hello dan akan melaksanakannya. Kaedah ini akan mengembalikan teks "hello". Teks ini akan diterima oleh ViewResolver, yang akan memberitahu pelayan tempat untuk mencari fail jsp yang perlu dipaparkan kepada klien. Oleh itu, pelanggan akhirnya akan menerima halaman yang sangat dihargai itu.

Kesimpulan

Saya harap ia akan menjadi jelas daripada artikel bahawa perkataan "konteks" tidak menakutkan. Spesifikasi itu ternyata sangat berguna. Dan dokumentasi adalah kawan kita, bukan musuh kita. Saya harap ia akan menjadi jelas tentang apa Spring berdasarkan, cara ia menyambung, dan apa yang Servlet API mempunyai kaitan dengannya.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION