JavaRush /Java Blog /Random-ID /Dari Hello World hingga Spring Web MVC dan apa hubunganny...
Viacheslav
Level 3

Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet

Dipublikasikan di grup Random-ID
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 1

Perkenalan

Seperti kita ketahui, kesuksesan Java justru berkat evolusi perangkat lunak yang berupaya untuk terhubung ke jaringan. Oleh karena itu, kami akan menggunakan aplikasi konsol biasa “ Hello World ” sebagai dasar dan memahami apa yang diperlukan untuk menjadi aplikasi jaringan dari aplikasi konsol. Jadi, pertama-tama Anda perlu membuat proyek Java. Pemrogram adalah orang yang malas. Di zaman prasejarah, ketika beberapa orang sedang berburu mamut, yang lain duduk dan berusaha untuk tidak bingung dengan berbagai macam perpustakaan Java dan struktur direktori. Agar pengembang dapat mengontrol proses pembuatan aplikasi, sehingga ia dapat dengan mudah menulis "Saya ingin perpustakaan versi 2 ini dan itu", mereka datang dengan alat khusus - membangun sistem. Dua yang paling terkenal adalah Maven dan Gradle . Untuk artikel ini kita akan menggunakan Gradle. Jika sebelumnya kita harus membuat struktur direktori sendiri, sekarang Gradle, menggunakan Plugin Gradle Init, memungkinkan kita membuat proyek Java dengan struktur direktori dan kelas utama dasar dalam satu perintah: gradle init --type java-application Perintah ini melakukan inisialisasi (init) untuk kami aplikasi Java (java-application ) dengan konsol Hello World. Setelah selesai, sebuah file akan muncul di direktori - build.gradle . Ini adalah skrip build kami - yaitu skrip khusus untuk membuat aplikasi dengan deskripsi tindakan apa yang perlu dilakukan untuk ini. Mari kita buka dan tambahkan baris ke dalamnya: jar.baseName = 'webproject' Gradle memungkinkan Anda melakukan berbagai tindakan pada suatu proyek dan tindakan ini disebut tugas . Dengan menjalankan perintah (tugas), file JAR akan dibuat gradle builddi direktori /build/libs . Dan, seperti yang Anda duga, namanya sekarang menjadi webproject.jar . Namun jika kita mengeksekusi java -jar ./build/libs/webproject.jar, kita akan mendapatkan error: no main manifest attribute. Ini karena untuk aplikasi java Anda perlu melampirkan manifes - ini adalah deskripsi tentang cara bekerja dengan aplikasi tersebut, cara melihatnya. Kemudian JVM yang akan mengeksekusi aplikasi java akan mengetahui kelas mana yang menjadi entry point ke program dan informasi lainnya (misalnya classpath). Jika kita melihat lebih dekat isi skrip build, kita akan melihat plugin-plugin yang terhubung. Misalnya: apply plugin: 'java' Jika kita membuka halaman Plugin Gradle Java , kita dapat melihat bahwa kita dapat mengonfigurasi manifes:
jar {
    manifest {
        attributes 'Main-Class': 'App'
    }
}
Kelas utama, titik masuk ke program, dibuat untuk kita oleh Plugin Gradle Init. Dan itu bahkan ditentukan dalam parameter mainClassName. Tapi ini tidak cocok untuk kami, karena... pengaturan ini mengacu pada plugin lain, Gradle Application Plugin . Jadi, kita mempunyai aplikasi Java yang menampilkan Hello World di layar. Aplikasi Java ini dikemas dalam JAR (Java ARchive). Sederhana, berbasis konsol, tidak mutakhir. Bagaimana cara mengubahnya menjadi aplikasi web?
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 2

API Servlet

Agar Java dapat bekerja dengan jaringan, spesifikasi yang disebut Servlet API muncul di zaman kuno . Spesifikasi inilah yang menjelaskan interaksi klien-server, menerima pesan dari klien (misalnya, browser) dan mengirimkan respons (misalnya, dengan teks halaman). Tentu saja banyak yang berubah sejak saat itu, namun intinya agar aplikasi Java menjadi aplikasi web digunakan Servlet API. Agar tidak berspekulasi tanpa dasar, mari kita ambil spesifikasinya: JSR-000340 JavaTM Servlet 3.1 . Pertama-tama, kami tertarik pada " Bab 1: Ikhtisar ". Ini menggambarkan konsep dasar yang harus kita pahami. Pertama, apa itu servlet? Bab " 1.1 Apa itu Servlet? " menyatakan bahwa Servlet adalah komponen Java yang dikelola oleh sebuah container dan menghasilkan konten dinamis. Seperti komponen Java lainnya, servlet adalah kelas Java yang dikompilasi menjadi bytecode dan dapat dimuat ke server web menggunakan teknologi Java. Penting agar servlet berinteraksi dengan klien web (misalnya, browser) dalam kerangka paradigma permintaan/respons, yang diimplementasikan oleh Kontainer Servlet. Ternyata Servlet tinggal di semacam Kontainer Servlet. Apa ini? Pada bab " 1.2 Apa itu Servlet Container? " dikatakan bahwa Servlet Container adalah beberapa bagian dari server web atau server aplikasi yang menyediakan layanan jaringan melalui mana permintaan dikirim dan tanggapan dikirim. Kontainer Servlet ini mengatur siklus hidup servlet. Semua Kontainer Servlet diperlukan untuk mendukung protokol HTTP minimal, tetapi mungkin mendukung yang lain. Misalnya HTTPS. Penting juga bahwa Kontainer Servlet dapat menerapkan pembatasan terkait keamanan apa pun pada lingkungan tempat servlet dijalankan. Penting juga bahwa menurut “ 10.6 File Arsip Aplikasi Web ” aplikasi web harus dikemas dalam file WAR (Web ARchive). Artinya, sekarang kita perlu menghapus jar dan plugin aplikasi kita untuk hal lain. Dan ini adalah plugin Gradle WAR . Dan alih-alih jar.baseName tentukan war.baseName Karena Karena kami tidak lagi menggunakan plugin jar, kami juga telah menghapus pengaturan manifes. Saat kami meluncurkan JAR, Java Virtual Machine (JVM) perlu diberi tahu melalui manifes cara bekerja dengan aplikasi kami. Karena JVM yang menjalankannya. Aplikasi web tampaknya dijalankan oleh semacam server web. Ternyata dia perlu memberitahunya cara bekerja dengan aplikasi web kita? Dan ternyata ya. Aplikasi web memiliki manifesto khusus mereka sendiri. Ini disebut Deployment Descriptor . Seluruh bagian didedikasikan untuk itu: “ 14. Deployment Descriptor ”. Ada bagian penting: " Bab 10:". Ini berbicara tentang apa itu aplikasi web dari sudut pandang Servlet API. Misalnya, dalam bab " 10.5 Struktur Direktori " ditunjukkan di mana Deployment Descriptor seharusnya berada: /WEB-INF/web.xml. Di mana menempatkan WEB-INF? Seperti yang dinyatakan dalam plugin Gradle WAR, ia menambahkan tata letak baru : src/main/webappOleh karena itu, mari kita buat direktori seperti itu, di dalamnya kita akan membuat direktori WEB-INF, dan di dalamnya kita akan membuat file web.xml. Penting bahwa direktori tersebut disebut WEB-INF, dan bukan META-INF! Mari kita salin dari " 14.5.1 Contoh Dasar " Contoh XML:
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 3
Seperti yang bisa kita lihat, dokumen XML digunakan untuk konfigurasi. Sebuah dokumen XML, agar dianggap valid (Valid), harus sesuai dengan beberapa “skema”. Anda dapat menganggap ini sebagai semacam antarmuka untuk dokumen XML. Skema menentukan elemen apa yang bisa ada dalam dokumen XML, tipe data apa yang bisa menentukan elemen, urutan, persyaratan, dan aspek lainnya. Contoh yang disalin dari dokumentasi menunjukkan versi 2.5, tetapi kami ingin menggunakan versi 3.1. Tentu saja, spesifikasinya berubah seiring dengan perubahan versi, dan fitur-fitur baru ditambahkan. Oleh karena itu, Anda perlu menggunakan skema selain yang digunakan untuk versi 2.5 (web-app_2_5.xsd). Skema apa yang harus saya gunakan untuk versi 3.1? Dokumentasi akan membantu kita dalam hal ini, bab “ 14.3 Deployment Descriptor ”, yang menyatakan specification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd Artinya, kita perlu mengganti link ke skema dengan xsd yang ditentukan di mana-mana, jangan lupa mengubahnya version="2.5"ke 3.1, dan juga mengubah namespace di mana-mana ( xmlns dan di xsi:schemaLocation). Mereka menunjukkan di dalam namespace mana kita akan bekerja (sederhananya, nama elemen apa yang dapat kita gunakan). Jika Anda membuka file skema, targetNamespace akan berisi namespace yang sama yang harus kita tentukan:
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 4
Seperti yang kita ingat, di Manifest file Jar kita menulis kelas mana yang ingin kita gunakan. Apa yang harus dilakukan di sini? Di sini kita perlu menentukan kelas servlet mana yang ingin kita gunakan ketika kita menerima permintaan dari klien web. Penjelasannya dapat dibaca pada bab “ 14.4 Deployment Descriptor Diagram ”. Ini akan terlihat seperti ini:
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 5
Semuanya sederhana di sini. Serverlet dideklarasikan, dan kemudian dipetakan ke template tertentu. Dalam hal ini, di /app. Ketika template dijalankan, metode servlet akan dijalankan. Demi kecantikan, kelas App harus ditransfer ke paket, jangan lupa untuk memperbaiki konfigurasi xml. Tapi bukan itu saja. Aplikasi harus berupa servlet. Apa artinya menjadi servlet? Artinya kita harus mewarisi dari HttpServlet . Contohnya bisa dilihat pada bab " 8.1.1 @WebServlet ". Berdasarkan itu, kelas Aplikasi kita akan terlihat 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);
		}
	}
}
Tapi proyek kami belum siap. Karena kita sekarang bergantung pada Servlet API versi 3.1. Ini berarti bahwa dalam skrip build, kita perlu menunjukkan ketergantungan pada API Servlet. JVM perlu mengetahui bahwa apa yang Anda tulis dalam kode itu benar dan bagaimana cara menggunakannya. Seperti yang kita ingat, spesifikasi pada dasarnya hanyalah antarmuka yang menjelaskan cara kerja semuanya. Dan implementasinya terletak pada sisi server web. Oleh karena itu, tanpa Servlet API akan ada Temukan perpustakaan yang diperlukan di Maven Central: javax.servlet-api . Dan tambahkan entri ke blok dependensi . Di repositori Maven, seperti yang Anda lihat, dikatakan disediakan. Sebelum menggunakan ketergantungan, Anda harus menentukan cakupannya. Gradle tidak memiliki cakupan bernama "disediakan", tetapi ia memiliki cakupan " hanya kompilasi ". Oleh karena itu, kami akan menunjukkan: providedCompile 'javax.servlet:javax.servlet-api:3.1.0' Ugh, semuanya tampak baik-baik saja? Gradle Build akan membangun proyek kita menjadi file WAR. Dan apa yang harus kita lakukan selanjutnya? Pertama, kita membutuhkan Server Web. Di Google kami menulis " daftar java server web " dan melihat daftar server web. Mari kita pilih dari daftar ini, misalnya TomCat . Buka situs web Apache Tomcat , unduh versi terbaru (saat ini versi 9) sebagai arsip zip (jika untuk Windows). Buka paketnya ke beberapa direktori. Hore, kami memiliki server web. Dari direktori server web di subdirektori bin , kami menjalankan catalina dari baris perintah dan melihat opsi yang tersedia. Mari lakukan: catalina start. Setiap server web memiliki direktori yang dipantau oleh server web. Jika file aplikasi web muncul di sana, server web mulai menginstalnya. Instalasi ini disebut penerapan atau deployment . Ya ya, itu sebabnya " deskriptor penerapan ". Yaitu cara men-deploy aplikasi dengan benar. Di Tomcat direktori ini adalah webapps . Mari kita salin perang yang kita buat menggunakan gradle build di sana. Setelah ini, di log kita akan melihat sesuatu seperti: Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [время] ms Untuk memahami lebih baik, di direktori Tomcat kita akan mengedit file \conf\tomcat-users.xml, menambahkan baris berikut:
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 6
Sekarang kita restart server (catalina stop, catalina start) dan masuk ke alamatnya, http://127.0.0.1:8080/manager disini kita akan melihat path semua aplikasi. Proyek web kami kemungkinan besar diberi jalur /proyek web. Apa jalan ini? Spesifikasi pada bab " 10.1 Aplikasi Web Dalam Server Web " menyatakan bahwa aplikasi web dikaitkan dengan beberapa jalur dalam aplikasi (dalam hal ini, /proyek web). Semua permintaan melalui jalur ini akan dikaitkan dengan ServletContext yang sama. Jalur ini juga disebut konteksRoot . Dan menurut " 10.2 Hubungan dengan ServletContext ", wadah servlet menghubungkan aplikasi web dan ServletContext satu lawan satu. Artinya, setiap aplikasi web memiliki ServletContext-nya sendiri. Apa itu ServletContext ? Seperti yang dinyatakan dalam spesifikasi, ServletContext adalah objek yang menyediakan "tampilan aplikasi " pada servlet di mana servlet dijalankan. Konteks Servlet dijelaskan lebih rinci di Bab 4 spesifikasi API Servlet. Anehnya, Servlet API di versi 3.1 tidak lagi memerlukan kehadiran web.xml. Misalnya, Anda dapat mendefinisikan 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 direkomendasikan pada topik: " Wawancara Java EE - JEE Servlet API (Pertanyaan dan Jawaban) ". Jadi, kami memiliki Servlet - yang bertanggung jawab atas respons apa yang diberikan kepada klien web. Kami memiliki ServletContainer yang menerima permintaan dari pengguna, mencocokkan jalur yang diakses dengan jalur ke servlet, dan jika ditemukan kecocokan, jalankan Servlet. Bagus. Tempat apa yang ditempati Musim Semi dalam gambaran dunia ini ?

MVC Web Musim Semi

Bagus, kami memiliki aplikasi web. Sekarang kita perlu menghubungkan Spring. Bagaimana kita bisa melakukan ini? Pertama, Anda perlu mengetahui cara menghubungkan Spring dengan benar ke proyek Anda. Ternyata sebelumnya hal ini dapat dilakukan sesuai dengan dokumentasi proyek platform Spring , tetapi sekarang “ Platform akan mencapai akhir masa pakainya yang didukung pada tanggal 9 April 2019 ”, artinya, tidak disarankan untuk melakukannya menggunakannya, karena itu akan segera tidak lagi didukung. Satu-satunya jalan keluar adalah " Pengguna Platform didorong untuk mulai menggunakan manajemen ketergantungan Spring Boot ". Oleh karena itu, mari beralih ke dokumentasi Spring Boot . Izinkan saya menjelaskan bahwa kami tidak menggunakan Spring Boot itu sendiri, tetapi hanya Manajemen Ketergantungan dari Spring Boot. Artinya, proyek Spring Boot dapat memberikan pengetahuan tentang versi perpustakaan mana yang akan digunakan (termasuk Spring MVC). Di sana kita akan menemukan 3.2. Menggunakan manajemen ketergantungan Spring Boot secara terpisah . Menurut dokumentasi, tambahkan yang berikut ini ke skrip build:
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, yaitu. Kami tidak menggunakan Spring Boot itu sendiri, tetapi kami menggunakan manajemen ketergantungan dari sana. Manajemen ketergantungan ini juga disebut BOM - " Bill Of Materials ". Sekarang kami siap untuk menghubungkan proyek Spring Web MVC itu sendiri. Spring Web MVC adalah bagian dari proyek Spring Framework dan kami tertarik pada bagian " Web Servlet ". Mari tambahkan ketergantungan pada skrip build: compile 'org.springframework:spring-webmvc'. Seperti yang bisa kita lihat, kita menetapkan cakupan kompilasi, karena server web tidak memberi kami Spring. Proyek kami dipaksa untuk menyertakan perpustakaan Spring di dalamnya. Selanjutnya, penting bagi kita untuk membaca bagian " 1.2. DispatcherServlet ", yang menyatakan bahwa Spring MVC dibangun di sekitar pola " Front controller ", di mana terdapat semacam servlet pusat yang menyediakan konfigurasi dan delegasi ke komponen lain . Dispatcher dapat diterjemahkan sebagai petugas operator. Jadi, pertama-tama, di web.xml kami mendeklarasikan:
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 7
Seperti yang bisa kita lihat, ini sebenarnya adalah Listener biasa yang ditentukan dalam spesifikasi Servlet API. Lebih tepatnya, ini adalah ServletContextListener, yang dipicu untuk menginisialisasi Konteks Servlet untuk aplikasi web kita. Selanjutnya, Anda perlu menentukan pengaturan yang akan memberi tahu Spring di mana konfigurasi xml khusus dengan pengaturan berada:
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 8
Seperti yang Anda lihat, ini hanyalah pengaturan biasa yang disimpan di tingkat Konteks Servlet, tetapi akan digunakan oleh Spring saat menginisialisasi Konteks Aplikasi. Sekarang Anda perlu mendeklarasikan, alih-alih semua servlet, satu operator yang mendistribusikan semua permintaan lainnya.
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 9
Dan tidak ada keajaiban di sini. Jika kita lihat, ini adalah HttpServlet, tempat Spring melakukan banyak hal yang menjadikannya sebuah kerangka kerja. Yang tersisa hanyalah menghubungkan (memetakan) templat URL tertentu dengan servlet:
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 10
Semuanya seperti yang kita lakukan sebelumnya. Sekarang mari kita buat sesuatu yang harus ditampilkan oleh server web kita. Misalnya, mari kita buat subdirektori halaman di WEB-INF kita, dan akan ada file hello.jsp. Kontennya bisa menjadi yang paling primitif. Misalnya di dalam tag html terdapat tag h1 dengan teks " Hello World ". Dan jangan lupa untuk membuat file applicationContext.xmlyang sudah kita tentukan tadi. Mari kita ambil contoh dari dokumentasi Spring: " 1.10.3. Secara otomatis mendeteksi kelas dan mendaftarkan definisi kacang ".
Dari Hello World hingga Spring Web MVC dan apa hubungannya dengan servlet - 11
Karena kami mengaktifkan deteksi otomatis dengan cara ini, sekarang kami dapat membuat 2 kelas (mereka akan dianggap Spring Beans karena penggunaan anotasi Spring khusus), yang sekarang akan dibuat sendiri oleh Spring dan menyesuaikan aplikasi kami dengan bantuan mereka:
  1. Konfigurasi web misalnya 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 dijelaskan dalam dokumentasi Spring Framework: " 1.11.MVC Config ".

    Di sini kita mendaftarkan ViewResolver, yang akan membantu menentukan di mana halaman jsp berada. Metode kedua memastikan bahwa " Servlet default " diaktifkan.

    Anda dapat membaca lebih lanjut tentang ini di sini: " Apa kebutuhan dan kegunaan default-servlet-handler ".

  2. Pengontrol HelloController untuk menjelaskan pemetaan permintaan ke JSP tertentu

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

    Di sini kita telah menggunakan anotasi @Controller yang dijelaskan dalam dokumentasi di bab " 1.4. Pengontrol Beranotasi ".

Sekarang, ketika aplikasi kita di-deploy, ketika kita mengirim permintaan /webproject/hello(di mana /webproject adalah akar konteksnya), DispatcherServlet akan diproses terlebih dahulu. Dia, sebagai operator utama, akan menentukan bahwa kami /* cocok dengan permintaan saat ini, yang berarti DispatcherServlet harus melakukan sesuatu. Kemudian ia akan menelusuri semua pemetaan yang ditemukannya. Ia akan melihat bahwa ada HelloController dengan metode pegangan yang dipetakan ke /hello dan akan menjalankannya. Cara ini akan mengembalikan teks "halo". Teks ini akan diterima oleh ViewResolver, yang akan memberitahu server di mana mencari file jsp yang perlu ditampilkan ke klien. Dengan demikian, klien pada akhirnya akan menerima halaman yang sangat disayanginya.

Kesimpulan

Saya harap dari artikel ini jelas bahwa kata “konteks” tidak menakutkan. Spesifikasi itu ternyata sangat berguna. Dan dokumentasi adalah teman kita, bukan musuh kita. Saya harap akan jelas apa dasar Spring, bagaimana koneksinya, dan apa hubungannya dengan Servlet API.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION