Perkenalan
Java pernah memperkuat posisinya karena memilih aplikasi web sebagai prioritas. Sejak awal berdirinya, Java telah berjuang menemukan jalannya. Pertama, saya menyarankan applet. Hal ini memberikan banyak peluang bagi pengembang untuk membuat konten dinamis pada halaman HTML statis. Namun, applet tidak memenuhi harapan karena berbagai alasan: keamanan, biaya overhead, dan lain-lain. Kemudian pengembang bahasa Java mengusulkan alternatif -
Servlet API . Dan ternyata itu adalah keputusan yang tepat.
Servlet API adalah spesifikasi di mana setiap aplikasi web Java dibangun, baik itu aplikasi berbasis web atau layanan web yang mengembalikan informasi seperti yang diminta. Oleh karena itu, jalur untuk memahami cara kerja aplikasi web Java dimulai dengan memahami Servlet API.
API Servlet
Jadi,
Servlet API adalah apa yang ditawarkan oleh pengembang bahasa kepada pengembang Java. Servlet API adalah spesifikasi yang seharusnya menjawab pertanyaan utama kita. Anda dapat menemukannya di sini: "
Rilis Final JSR-000340 JavaTM Servlet 3.1 untuk Evaluasi ". Bab "
1.1 Apa itu Servlet? " mengatakan bahwa
servlet adalah komponen web berbasis teknologi Java yang membuat konten dinamis (yaitu konten). "Berbasis Java" berarti
servlet adalah kelas Java yang dikompilasi menjadi bytecode . Servlet dikelola oleh wadah servlet, terkadang disebut Mesin Servlet.
Kontainer servlet adalah ekstensi server web yang menyediakan fungsionalitas servlet. Pada gilirannya, servlet menyediakan interaksi dengan klien dalam paradigma permintaan/respons, yang diimplementasikan oleh wadah servlet. Pada bab "
1.2 Apa itu Servlet Container? " dikatakan bahwa
servlet container adalah bagian dari server web atau server aplikasi yang menyediakan layanan jaringan melalui mana permintaan dan tanggapan dikirim, permintaan dan tanggapan berbasis MIME dihasilkan dan diproses . Selain itu, container servlet mengatur siklus hidup servlet (yaitu memutuskan kapan akan membuatnya, menghapusnya, dll.). Semua container servlet harus mendukung protokol HTTP untuk menerima permintaan dan mengirim tanggapan. Di sini saya ingin menambahkan bahwa MIME adalah sebuah standar, spesifikasi yang memberitahukan bagaimana informasi harus dikodekan dan pesan diformat sehingga dapat dikirim melalui Internet.
Server web
Server web adalah server yang menerima permintaan HTTP dari klien dan memberikan respons HTTP kepada mereka (biasanya bersama dengan halaman HTML, gambar, file, atau data lainnya). Sumber daya yang diminta diidentifikasi berdasarkan URL. Salah satu server web terpopuler dengan dukungan Servlet API adalah
Apache Tomcat . Kebanyakan server web adalah mesin kompleks yang terdiri dari berbagai komponen, yang masing-masing menjalankan fungsi tertentu. Misalnya:
Konektor
— Pada masukan kami memiliki Konektor (yaitu konektor) yang menerima permintaan masuk dari klien. Konektor HTTP di Tomcat diimplementasikan menggunakan komponen "Coyote". Konektor menerima data dari klien dan meneruskannya ke Mesin Tomcat.
Servlet Container - Mesin Tomcat, pada gilirannya, memproses permintaan yang diterima dari klien menggunakan komponen "Catalina", yang merupakan wadah servlet. Lihat dokumentasi Tomcat: "
Ikhtisar Arsitektur " untuk lebih jelasnya. Ada server web lain yang mendukung spesifikasi Servlet API. Misalnya, "
Dermaga " atau "
Arus Bawah ". Arsitekturnya serupa, jadi dengan memahami prinsip bekerja dengan satu container servlet, Anda dapat beralih bekerja dengan container lainnya.
Aplikasi web
Jadi, agar kita dapat menjalankan aplikasi web, kita memerlukan server web yang mendukung API Servlet (yaitu, server yang memiliki komponen ekstensi yang mengimplementasikan dukungan API Servlet untuk server web). Bagus.
Apa sebenarnya aplikasi web itu? Menurut bab "
10 Aplikasi Web " dari spesifikasi Servlet API,
aplikasi Web adalah kumpulan servlet, halaman HTML, kelas, dan sumber daya lain yang membentuk aplikasi akhir di server Web. Menurut bab "
10.6 File Arsip Aplikasi Web ", aplikasi web dapat dikemas dalam Web ARchive (arsip dengan ekstensi WAR). Sebagaimana tercantum pada halaman "
Glosarium-219 ":
Artinya, WAR dibuat bukan JAR untuk menunjukkan bahwa ini adalah aplikasi web. Fakta penting berikutnya: kita harus memiliki struktur direktori tertentu di arsip WAR kita. Dalam spesifikasi Servlet API pada bab "
10.5 Struktur Direktori ". Bab ini mengatakan bahwa ada direktori khusus yang disebut "WEB-INF". Direktori ini istimewa karena tidak terlihat oleh klien dan tidak ditampilkan secara langsung, tetapi dapat diakses oleh kode servlet. Ia juga mengatakan apa isi direktori WEB-INF:
Dari seluruh daftar ini, kami sekarang tidak mengetahui dan tidak memahami item tentang beberapa file
web.xml yang disebut
deployment descriptor . Apa itu? Bab "
14. Deployment Descriptor " dikhususkan untuk deskriptor penerapan. Singkatnya,
deskriptor penerapan adalah file xml yang menjelaskan cara menyebarkan (yaitu, menjalankan) aplikasi web kita di server web. Misalnya, deskriptor penerapan menunjukkan URL mana yang harus digunakan untuk mengakses aplikasi kita, pengaturan keamanan yang terkait dengan aplikasi kita, dll. Bab "
14.2 Aturan untuk Memproses Penerapan " mengatakan bahwa web.xml akan divalidasi skema sebelum aplikasi kita dikonfigurasi dan diluncurkan (yaitu, akan dilakukan pemeriksaan bahwa konten web.xml ditulis dengan benar sesuai dengan skema) . Dan pada bab "
14.3 Deployment Descriptor " ditunjukkan bahwa diagramnya ada di sini:
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
Jika kita melihat isi file, kita dapat melihat:
Apa skema yang digunakan untuk file XML? Skema menunjukkan cara mengisi dokumen XML dengan benar: elemen apa yang dapat digunakan, tipe data apa yang dapat ditentukan dalam elemen, urutan elemen apa yang harus disusun, elemen apa yang diperlukan, dll. Anda dapat membandingkan skema dokumen XML dengan antarmuka di Java, karena skema di Java juga menentukan bagaimana kelas yang memenuhi antarmuka tertentu (yaitu, yang mengimplementasikan antarmuka tertentu) harus ditulis. Jadi, kita dipersenjatai dengan pengetahuan rahasia dan siap membuat aplikasi web pertama kita!
Membuat Aplikasi Web
Sulit membayangkan bekerja dengan aplikasi Java modern tanpa menggunakan sistem pembangunan proyek otomatis. Beberapa sistem yang paling populer adalah
Maven dan Gradle . Kami akan menggunakan Gradle untuk ulasan ini. Instalasi Gradle dijelaskan di
situs resminya . Untuk membuat aplikasi baru, kita memerlukan plugin bawaan Gradle: "
Build Init Plugin ". Untuk membuat aplikasi Java Anda perlu menjalankan perintah berikut:
gradle init --type java-application
Setelah membuat proyek, kita perlu mengedit file
build.gradle . Inilah yang disebut Build Script (untuk lebih jelasnya, lihat dokumentasi Gradle: "
Menulis Build Scripts "). File ini menjelaskan cara merakit proyek dan aspek lain dalam bekerja dengan proyek Java. Blok plugins menjelaskan "
Plugin Gradle " mana yang harus digunakan untuk proyek Gradle saat ini. Plugin memperluas kemampuan proyek kami. Misalnya, plugin defaultnya adalah "
java ". Plugin ini selalu digunakan jika kita membutuhkan dukungan Java. Namun kita tidak memerlukan plugin “
aplikasi ”, karena... deskripsinya menyatakan bahwa ini digunakan untuk membuat "aplikasi JVM yang dapat dieksekusi", yaitu. menjalankan aplikasi JVM. Kita perlu membuat aplikasi Web dalam bentuk arsip WAR. Dan jika kita mencari kata WAR pada dokumentasi Gradle, kita akan menemukan “
War Plugin ”. Oleh karena itu, kami akan menentukan plugin berikut:
plugins {
id 'java'
id 'war'
}
Juga di "
Pengaturan Default Plugin Perang " dikatakan bahwa direktori dengan semua konten aplikasi web harus "src/main/webapp", harus ada direktori WEB-INF yang sama di mana web.xml seharusnya berada terletak. Mari buat file seperti itu. Nanti kita isi lagi, karena... kami belum memiliki cukup informasi untuk ini. Di blok "dependensi" kami menunjukkan dependensi proyek kami, yaitu perpustakaan/kerangka kerja yang tanpanya aplikasi kami tidak dapat bekerja. Dalam hal ini, kami sedang menulis aplikasi web, yang berarti kami tidak dapat bekerja tanpa Servlet API:
dependencies {
providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
testCompile 'junit:junit:4.12'
}
provideCompile berarti bahwa ketergantungan tidak perlu disertakan dalam arsip WAR aplikasi web kami: ketergantungan hanya diperlukan untuk kompilasi. Dan ketika dijalankan, ketergantungan ini akan disediakan oleh orang lain (yaitu server web). Ya, kami meninggalkan informasi dalam skrip build tentang repositori dependensi mana yang ingin kami gunakan - semua dependensi yang ditentukan akan diunduh darinya:
repositories {
jcenter()
}
Kami menghapus semua yang lain dari file skrip build. Sekarang mari kita edit kelas src\main\java\App.java. Mari kita membuat servlet darinya. Spesifikasi API Servlet dalam bab "
BAB 2. Antarmuka Servlet " menyatakan bahwa Antarmuka Servlet memiliki implementasi dasar
HttpServlet , yang seharusnya cukup dalam banyak kasus dan pengembang hanya perlu mewarisinya. Dan di bab "
2.1.1 Metode Penanganan Permintaan Khusus HTTP " metode utama yang memproses permintaan masuk ditunjukkan. Jadi, mari kita menulis ulang kelas App.java:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.IOException;
public class App extends HttpServlet {
public String getGreeting() {
return "Hello world.";
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
out.println(this.getGreeting());
out.close();
}
}
Jadi sepertinya kami sudah menyiapkan semuanya. Yang tersisa hanyalah menulis deskriptor penerapan dengan benar. Dari diagram, salin teks berikut ke web.xml:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="..."
version="3.1">
...
</web-app>
Dan juga jalur ke skema yang ditunjukkan di dalamnya:
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
Sekarang mari kita lihat contoh tampilan web.xml dalam spesifikasi API Servlet. Contoh ini diberikan dalam bab "
14.5.1 Contoh Dasar ". Mari gabungkan apa yang ditunjukkan dalam diagram dengan contoh yang ditunjukkan dalam spesifikasi. Kami mendapatkan yang berikut:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>A Simple Web Application</display-name>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>App</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app</url-pattern>
</servlet-mapping>
</web-app>
Seperti yang Anda lihat, kami menggunakan skema dan skemaLocation yang ditentukan sebelumnya. Dan uraian unsur-unsurnya sendiri diambil dari contoh Bab 14.5.1. Jika kami melakukan semuanya dengan benar, kami akan menjalankan tugas perang bertahap tanpa kesalahan:
Meluncurkan aplikasi web
Bagaimana cara aplikasi web diluncurkan? Mari kita bahas opsi yang lebih rumit terlebih dahulu. Sebelumnya kami telah mengatakan bahwa ada server web Apache Tomcat yang mendukung API Servlet. Ini berarti bahwa kami dapat menyebarkan arsip perang yang kami kumpulkan (mereka juga mengatakan “menyebarkan”) di server ini. Pada halaman "
Unduh Tomcat ", unduh dari bagian "Distribusi Biner" jenis pengiriman "Inti" dalam format zip. Dan ekstrak arsip yang diunduh ke beberapa direktori, misalnya di C:\Apache-Tomcat-9.0.14. Sebelum memulai server, mari buka file untuk diedit
conf\tomcat-users.xml
dan tambahkan baris berikut ke dalamnya:
<user username="tomcat" password="tomcat" roles="tomcat,manager-gui,admin-gui"/>
Sekarang, pada baris perintah, buka direktori bin dan jalankan
catalina.bat start
. Secara default, konsol server akan tersedia di
http://localhost:8080/manager
. Login dan kata sandinya sama dengan yang kami tentukan di Tomcat-users.xml. Tomcat memiliki direktori "webapps", yang berisi aplikasi web. Jika kami ingin mengerahkan pasukan kami sendiri, kami harus menyalin arsip perang kami di sana. Ketika kita sebelumnya menjalankan perintah gradle war,
\build\libs\
arsip perang telah dibuat di direktori. Inilah yang perlu kita tiru. Setelah menyalin, segarkan halaman
http://localhost:8080/manager
dan lihat:
Setelah selesai
http://localhost:8080/javaweb/app
, kita akan beralih ke servlet kita, karena Kami sebelumnya “memetakan” (yaitu, memetakan) permintaan /app ke servlet Aplikasi. Ada cara yang lebih cepat untuk memeriksa cara kerja aplikasi. Dan sistem perakitan membantu kami dalam hal ini lagi. Dalam skrip build proyek Gradle kita, kita dapat menambahkan plugin baru "
Gretty " ke bagian plugins:
id "org.gretty" version "2.3.1"
Dan sekarang kita dapat melakukan tugas gradle untuk menjalankan aplikasi kita:
gradle appRun
Lihat "
Tambahkan plugin gretty dan jalankan aplikasi " untuk detailnya.
API Musim Semi dan Servlet
Servlet adalah dasar dari segalanya. Dan bahkan Spring Framework yang sekarang populer tidak lebih dari sebuah add-on untuk Servlet API. Pertama-tama,
Spring Framework adalah ketergantungan baru untuk proyek kami. Oleh karena itu, mari tambahkan ke skrip build di blok dependensi:
compile 'org.springframework:spring-webmvc:5.1.3.RELEASE'
Dalam dokumentasi Spring Framework ada bab "
1.1. DispatcherServlet ". Dikatakan bahwa Spring Framework dibangun berdasarkan pola "pengontrol depan" - ini adalah ketika ada servlet pusat yang disebut "
DispatcherServlet ". Semua permintaan datang ke servlet ini, dan mendelegasikan panggilan ke komponen yang diperlukan. Anda tahu, bahkan di sini pun ada servlet. Anda perlu menambahkan pendengar ke deskriptor penerapan:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Ini adalah pendengar acara konteks servlet. Artinya, ketika Konteks Servlet dimulai, konteks Spring (WebApplicationContext) juga dimulai.
Apa itu Konteks Servlet? Hal ini dijelaskan dalam spesifikasi Servle API pada bab "
BAB 4. Konteks Servlet ". Konteks servlet adalah "tampilan" servlet terhadap aplikasi web di mana servlet berjalan. Setiap aplikasi web memiliki Konteks Servletnya sendiri. Selanjutnya, untuk mengaktifkan Spring Framework, Anda perlu menentukan parameter konteks - parameter inisialisasi untuk konteks servlet.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-context.xml</param-value>
</context-param>
Dan definisi
DispatcherServlet melengkapi konfigurasi :
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Dan sekarang kita hanya perlu mengisi file yang ditentukan di konteksConfigLocation. Cara melakukan ini dijelaskan dalam dokumentasi Spring Framework di bab "1.3.1. Deklarasi":
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="ru.javarush.javaweb"/>
<mvc:annotation-driven/>
</beans>
Penting di sini tidak hanya untuk menunjukkan paket mana yang akan dipindai, tetapi juga kita ingin berbasis anotasi, yaitu mengontrol anotasi tentang cara kerja Spring. Yang tersisa hanyalah membuat paket ru.javarush.javaweb dan menempatkan kelas pengontrol Spring di dalamnya:
package ru.javarush.javaweb;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SpringController {
@GetMapping("/app")
@ResponseBody
public String getGreeting() {
return "Hello world.";
}
}
Sekarang jalankan gradle appRun dan pergi ke alamatnya,
http://127.0.0.1:8080/javaweb/app
kita akan mendapatkan Hello World yang sama. Seperti yang Anda lihat, Spring Framework terkait erat dengan Servlet API dan menggunakannya untuk bekerja di atasnya.
Anotasi
Seperti yang telah kita lihat, anotasi sangatlah mudah. Dan kami bukan satu-satunya yang berpikir demikian. Oleh karena itu, dalam spesifikasi Servlet API, mulai dari versi 3.0, bab “
BAB 8 Anotasi dan pluggability ” muncul, yang menetapkan bahwa kontainer servlet harus mendukung kemampuan untuk menentukan apa yang sebelumnya ditentukan dalam Deployment Descriptor melalui anotasi. Dengan demikian, web.xml dapat dihapus sepenuhnya dari proyek, dan di atas kelas servlet Anda dapat menentukan anotasi
@WebServlet dan menunjukkan jalur mana yang akan dipetakan servlet. Semuanya tampak jelas di sini. Namun bagaimana jika kita menghubungkan Spring ke proyek, yang memerlukan pengaturan yang lebih kompleks? Di sini segalanya menjadi sedikit lebih rumit. Pertama, dokumentasi Spring mengatakan bahwa untuk mengonfigurasi Spring tanpa web.xml, Anda perlu menggunakan kelas Anda sendiri yang akan mengimplementasikan WebApplicationInitializer. Untuk lebih jelasnya lihat bab "
1.1. DispatcherServlet ". Ternyata ini adalah kelas Musim Semi. Lalu bagaimana Servlet API digunakan di sini? Faktanya,
ServletContainerInitializer telah ditambahkan ke Servlet API 3.0 . Menggunakan mekanisme khusus di Java (disebut
SPI ), Spring menentukan penginisialisasi wadah servlet yang disebut
SpringServletContainerInitializer
. Pada gilirannya, ia sudah mencari implementasi WebApplicationInitializer dan memanggil metode yang diperlukan serta melakukan pengaturan yang diperlukan. Lihat "
Bagaimana wadah servlet menemukan implementasi WebApplicationInitializer " untuk detail selengkapnya. Pengaturan di atas dapat dilakukan seperti ini:
package ru.javarush.javaweb.config;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
servletContext.addListener(new ContextLoaderListener(ctx));
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet =
servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
Sekarang, dengan menggunakan "
Konfigurasi berbasis Java " kami akan menunjukkan paket mana yang akan dipindai + mengaktifkan anotasi:
package ru.javarush.javaweb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "ru.javarush.javaweb.controllers")
public class AppConfig {
}
Dan SpringControllernya sendiri dipindahkan ke
ru.javarush.javaweb.controllers
, sehingga pada saat scanning konfigurasinya tidak menemukan dirinya sendiri, melainkan hanya mencari controller saja.
Meringkas
Saya harap ikhtisar ini memberi sedikit pencerahan tentang cara kerja aplikasi web di Java. Ini hanyalah puncak gunung es, namun tanpa memahami dasar-dasarnya, sulit untuk memahami cara kerja teknologi yang didasarkan pada fondasi ini. Servlet API adalah bagian utama dari setiap aplikasi web Java, dan kita telah melihat bagaimana kerangka kerja lain dapat masuk ke dalamnya. Untuk melanjutkan, Anda dapat melihat materi berikut:
#Viacheslav
GO TO FULL VERSION