การแนะนำ
ดังที่เราทราบ ความสำเร็จของ Java เกิดขึ้นอย่างแน่นอนด้วยวิวัฒนาการของซอฟต์แวร์ที่มุ่งมั่นที่จะเชื่อมต่อกับเครือข่าย ดังนั้นเราจะใช้แอปพลิเคชันคอนโซลปกติ " Hello World " เป็นพื้นฐานและทำความเข้าใจว่าจำเป็นต้องมีอะไรบ้างในการเป็นแอปพลิเคชันเครือข่ายจากแอปพลิเคชันคอนโซล ดังนั้นก่อนอื่นคุณต้องสร้างโปรเจ็กต์ Java โปรแกรมเมอร์เป็นคนขี้เกียจ ในสมัยก่อนประวัติศาสตร์ เมื่อบางคนกำลังล่าแมมมอธ บางตัวก็นั่งและพยายามไม่สับสนในไลบรารี Java และโครงสร้างไดเร็กทอรีที่หลากหลาย เพื่อให้นักพัฒนาสามารถควบคุมกระบวนการสร้างแอปพลิเคชันเพื่อที่เขาจะได้เขียนว่า "ฉันต้องการไลบรารี่ของเช่นนั้นและเวอร์ชัน 2" จึงมีเครื่องมือพิเศษ - สร้างระบบ สองอันที่มีชื่อเสียงที่สุดคือMavenและGradle สำหรับบทความนี้เราจะใช้ Gradle หากก่อนหน้านี้เราจะต้องสร้างโครงสร้างไดเร็กทอรีด้วยตัวเอง ตอนนี้ Gradle โดยใช้Gradle Init Pluginช่วยให้เราสามารถสร้างโปรเจ็กต์ Java ด้วยโครงสร้างไดเร็กทอรีและคลาสหลักพื้นฐานในคำสั่งเดียว:gradle init --type java-application
คำสั่งนี้ดำเนินการเริ่มต้น (init) สำหรับ เราเป็นแอปพลิเคชัน Java (java-application ) พร้อมคอนโซล Hello World หลังจากเสร็จสิ้น ไฟล์จะปรากฏในไดเร็กทอรี - build.gradle นี่คือสคริปต์การสร้าง ของเรา - นั่นคือสคริปต์บางตัวสำหรับการสร้างแอปพลิเคชันพร้อมคำอธิบายว่าต้องดำเนินการอะไรบ้างสำหรับสิ่งนี้ ลองเปิดมันและเพิ่มบรรทัดลงไป: jar.baseName = 'webproject'
Gradle ช่วยให้คุณสามารถดำเนินการต่าง ๆ ในโครงการและการกระทำเหล่านี้เรียกว่างาน โดยการรันคำสั่ง (งาน) ไฟล์ JAR จะถูกสร้างขึ้น gradle build
ใน ไดเร็กทอรี /build/libs และอย่างที่คุณเดาได้ ตอนนี้ชื่อของมันจะเป็นwebproject.jar แต่ถ้าเราดำเนินการjava -jar ./build/libs/webproject.jar
เราจะได้รับข้อผิดพลาด: no main manifest attribute
. เนื่องจากสำหรับแอปพลิเคชัน Java คุณต้องแนบรายการ - นี่คือคำอธิบายเกี่ยวกับวิธีการทำงานกับแอปพลิเคชัน วิธีการรับรู้ จากนั้น JVM ซึ่งจะรันแอปพลิเคชัน Java จะรู้ว่าคลาสใดเป็นจุดเริ่มต้นของโปรแกรมและข้อมูลอื่น ๆ (เช่น classpath) หากเราพิจารณาเนื้อหาของสคริปต์บิลด์ให้ละเอียดยิ่งขึ้น เราจะเห็นว่ามีการเชื่อมต่อปลั๊กอินอยู่ ตัวอย่างเช่น: apply plugin: 'java'
ถ้าเราไปที่ หน้า Gradle Java Plugin เราจะเห็นว่าเราสามารถกำหนดค่ารายการได้:
jar {
manifest {
attributes 'Main-Class': 'App'
}
}
คลาสหลักซึ่งเป็นจุดเริ่มต้นของโปรแกรมถูกสร้างขึ้นสำหรับเราโดย Gradle Init Plugin และยังระบุไว้ในพารามิเตอร์ mainClassName ด้วย แต่สิ่งนี้ไม่เหมาะกับเราเพราะว่า... การตั้งค่านี้อ้างอิงถึงปลั๊กอินอื่นGradle Application Plugin ดังนั้นเราจึงมีแอปพลิเคชัน Java ที่แสดง Hello World บนหน้าจอ แอปพลิเคชัน Java นี้บรรจุอยู่ใน JAR (Java ARchive) มันเรียบง่าย ใช้คอนโซล และไม่ทันสมัย จะเปลี่ยนให้เป็นเว็บแอปพลิเคชั่นได้อย่างไร?

เซิร์ฟเล็ต API
เพื่อให้ Java สามารถทำงานร่วมกับเครือข่ายได้ ข้อกำหนดที่เรียกว่าServlet API ปรากฏขึ้นในสมัย โบราณ ข้อกำหนดนี้อธิบายการโต้ตอบระหว่างไคลเอ็นต์และเซิร์ฟเวอร์ การรับข้อความจากไคลเอ็นต์ (เช่น เบราว์เซอร์) และการส่งการตอบกลับ (เช่น พร้อมข้อความในหน้าเว็บ) โดยปกติแล้วมีการเปลี่ยนแปลงมากมายตั้งแต่นั้นมา แต่ประเด็นก็คือเพื่อให้แอปพลิเคชัน Java กลายเป็นเว็บแอปพลิเคชันนั้น Servlet API จึงถูกใช้ เพื่อไม่ให้เป็นการคาดเดาอย่างไม่มีมูล เรามาเลือกข้อมูลจำเพาะนั้นกันดีกว่า: JSR-000340 JavaTM Servlet 3.1 ก่อนอื่นเราสนใจ " บทที่ 1: ภาพรวม " มันอธิบายแนวคิดพื้นฐานที่เราต้องเข้าใจ ก่อนอื่น servlet คืออะไร? บทที่ " 1.1 Servlet คืออะไร " บอกว่าServletเป็นส่วนประกอบ Java ที่ได้รับการจัดการโดยคอนเทนเนอร์และสร้างเนื้อหาแบบไดนามิก เช่นเดียวกับส่วนประกอบ Java อื่นๆ servlet คือคลาส Java ที่ถูกคอมไพล์เป็น bytecode และสามารถโหลดลงในเว็บเซิร์ฟเวอร์โดยใช้เทคโนโลยี Java สิ่งสำคัญคือเซิร์ฟเล็ตโต้ตอบกับเว็บไคลเอ็นต์ (เช่น เบราว์เซอร์) ภายในกรอบของกระบวนทัศน์คำขอ/ตอบกลับ ซึ่งดำเนินการโดยคอนเทนเนอร์เซิร์ฟเล็ต ปรากฎว่า Servlets อาศัยอยู่ใน Servlet Container บางประเภท นี่คืออะไร? ในบท " 1.2 Servlet Container คืออะไร " ว่ากันว่าServlet Containerเป็นส่วนหนึ่งของเว็บเซิร์ฟเวอร์หรือแอปพลิเคชันเซิร์ฟเวอร์ที่ให้บริการเครือข่ายซึ่งมีการส่งคำขอและส่งการตอบสนอง Servlet Container นี้จัดการวงจรชีวิตของเซิร์ฟเล็ต Servlet Containers ทั้งหมดจำเป็นต้องรองรับโปรโตคอล HTTP เป็นอย่างน้อย แต่อาจรองรับโปรโตคอลอื่นได้ ตัวอย่างเช่น HTTPS สิ่งสำคัญคือ Servlet Container สามารถกำหนดข้อจำกัดที่เกี่ยวข้องกับความปลอดภัยบนสภาพแวดล้อมที่เซิร์ฟเล็ตถูกดำเนินการได้ สิ่งสำคัญคือตาม " 10.6 Web Application Archive File " เว็บแอปพลิเคชันจะต้องได้รับการบรรจุในไฟล์ WAR (Web ARchive) นั่นคือตอนนี้เราต้องลบ jar และปลั๊กอินแอปพลิเคชันของเราเพื่ออย่างอื่น และนี่คือปลั๊กอิน Gradle WAR และแทนที่จะระบุ jar.baseName ให้ระบุ war.baseName Because เนื่องจากเราไม่ได้ใช้ปลั๊กอิน jar อีกต่อไป เราจึงได้ลบการตั้งค่ารายการออกด้วย เมื่อเราเปิดตัว JAR จำเป็นต้องบอก Java Virtual Machine (JVM) ถึงวิธีทำงานกับแอปพลิเคชันของเราผ่านทาง Manifest เพราะ JVM กำลังรันอยู่ เห็นได้ชัดว่าเว็บแอปพลิเคชันนั้นดำเนินการโดยเว็บเซิร์ฟเวอร์บางประเภท ปรากฎว่าเขาจำเป็นต้องบอกวิธีการทำงานกับเว็บแอปพลิเคชันของเราหรือไม่? และปรากฎว่าใช่ เว็บแอปพลิเคชันมีแถลงการณ์พิเศษของตัวเอง เรียกว่าDeployment Descriptor ส่วนทั้งหมดมีไว้สำหรับมัน: " 14. Descriptor การปรับใช้ " มีส่วนสำคัญ: " บทที่ 10:" มันพูดถึงว่าเว็บแอปพลิเคชันคืออะไรจากมุมมองของ Servlet API ตัวอย่างเช่นในบท " 10.5 Directory Structure " มีการระบุว่า Deployment Descriptor ควรอยู่ที่ใด:/WEB-INF/web.xml
จะวาง WEB-INF ไว้ที่ไหน? ตามที่ระบุไว้ในปลั๊กอิน Gradle WAR มันจะเพิ่มเลย์เอาต์ ใหม่ : src/main/webapp
ดังนั้นเรามาสร้างไดเร็กทอรีดังกล่าวภายในเราจะสร้างไดเร็กทอรี WEB-INF และภายในเราจะสร้างไฟล์ web.xml สิ่งสำคัญคือไดเร็กทอรี เรียกว่า WEB-INF ไม่ใช่ META-INF ลองคัดลอกมาจากตัวอย่าง XML " 14.5.1 A Basic Example ":

specification is available at http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd
นั่นคือ เราจำเป็นต้องแทนที่ลิงก์ไปยังสคีมาด้วย xsd ที่ระบุทุกที่ โดยไม่ลืมที่จะเปลี่ยนversion="2.5"
เป็น 3.1 และยังเปลี่ยนเนมสเปซทุกที่ ( xmlns และใน xsi:schemaLocation) พวกเขาระบุว่าเราจะทำงานภายในเนมสเปซใด (พูดง่ายๆ ก็คือ ชื่อองค์ประกอบใดที่เราสามารถใช้ได้) หากคุณเปิดไฟล์สคีมา targetNamespace จะมีเนมสเปซเดียวกันกับที่เราควรระบุ:


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);
}
}
}
แต่โครงการของเรายังไม่พร้อม เนื่องจากตอนนี้เราพึ่งพา Servlet API เวอร์ชัน 3.1 ซึ่งหมายความว่าในสคริปต์บิลด์ของเรา เราจำเป็นต้องระบุการพึ่งพา Servlet API JVM จำเป็นต้องรู้ว่าสิ่งที่คุณเขียนในโค้ดนั้นถูกต้องและใช้งานอย่างไร อย่างที่เราจำได้ ข้อมูลจำเพาะนั้นเป็นเพียงอินเทอร์เฟซที่อธิบายว่ามันควรทำงานอย่างไร และการใช้งานนั้นอยู่ทางฝั่งเว็บเซิร์ฟเวอร์ ดังนั้น หาก ไม่มีServlet API จะมีการค้นหาไลบรารีที่ต้องการบน Maven Central: javax.servlet-api และ เพิ่มรายการลงใน บล็อก การพึ่งพา ในพื้นที่เก็บข้อมูล Maven อย่างที่คุณเห็น มันบอกว่าให้มา ก่อนที่จะใช้การขึ้นต่อกัน คุณต้องระบุขอบเขต Gradle ไม่มีขอบเขตชื่อ "ระบุ" แต่มีขอบเขต " คอมไพล์เท่านั้น " ดังนั้นเราจะระบุว่า: providedCompile 'javax.servlet:javax.servlet-api:3.1.0'
เอ่อ ดูเหมือนว่าทุกอย่างจะเรียบร้อยดีใช่ไหม? Gradle Build จะสร้างโปรเจ็กต์ของเราเป็นไฟล์ WAR และเราควรทำอย่างไรต่อไปกับมัน? ก่อนอื่นเราต้องมีเว็บเซิร์ฟเวอร์ ใน Google เราเขียน " รายการเว็บเซิร์ฟเวอร์ java " และดูรายการเว็บเซิร์ฟเวอร์ เรามาเลือกจากรายการนี้กันเช่นTomCat ไปที่ เว็บไซต์ Apache Tomcatดาวน์โหลดเวอร์ชันล่าสุด (ปัจจุบันคือเวอร์ชัน 9) เป็นไฟล์ zip (หากสำหรับ Windows) แตกไฟล์ลงในไดเร็กทอรีบางแห่ง ไชโย เรามีเว็บเซิร์ฟเวอร์ จากไดเรกทอรีของเว็บเซิร์ฟเวอร์ใน ไดเรกทอรีย่อย bin เราจะดำเนินการ catalinaจากบรรทัดคำสั่งและดูตัวเลือกที่มี มาทำกัน: catalina start
. แต่ละเว็บเซิร์ฟเวอร์มีไดเร็กทอรีที่เว็บเซิร์ฟเวอร์ตรวจสอบ หากไฟล์แอปพลิเคชันเว็บปรากฏขึ้น แสดงว่าเว็บเซิร์ฟเวอร์เริ่มทำการติดตั้ง การติดตั้งนี้เรียกว่าการปรับใช้หรือการปรับใช้ ใช่ ใช่ นั่นเป็นเหตุผลว่าทำไม " Descriptor การนำไปใช้งาน " นั่นคือวิธีการปรับใช้แอปพลิเคชันอย่างเหมาะสม ใน Tomcat ไดเรกทอรีนี้คือwebapps มาคัดลอกสงครามที่เราทำโดยใช้ gradle build ที่นั่น หลังจากนี้ เราจะเห็นบางอย่างในบันทึก: Deployment of web application archive [tomcat\webapps\webproject.war] has finished in [время] ms
เพื่อให้เข้าใจดียิ่งขึ้น เราจะแก้ไขไฟล์ในไดเร็กทอรี Tomcat \conf\tomcat-users.xml
โดยเพิ่มบรรทัดต่อไปนี้:

http://127.0.0.1:8080/manager
นี่เราจะเห็นเส้นทางของแอปพลิเคชันทั้งหมด เว็บโปรเจ็กต์ของเรามักจะได้รับเส้นทาง /webproject เส้นทางนี้คืออะไร? ข้อกำหนดในบท " 10.1 เว็บแอปพลิเคชันภายในเว็บเซิร์ฟเวอร์ " ระบุว่าเว็บแอปพลิเคชันเชื่อมโยงกับเส้นทางบางอย่างภายในแอปพลิเคชัน (ในกรณีนี้คือ /webproject) คำขอทั้งหมดผ่านเส้นทางนี้จะเชื่อมโยงกับ ServletContext เดียวกัน เส้นทางนี้เรียกอีกอย่างว่าcontextRoot และตาม " 10.2 ความสัมพันธ์กับ ServletContext " คอนเทนเนอร์เซิร์ฟเล็ตเกี่ยวข้องกับเว็บแอปพลิเคชันและ ServletContext แบบหนึ่งต่อหนึ่ง นั่นคือแต่ละเว็บแอปพลิเคชันมี ServletContext ของตัวเอง ServletContextคืออะไร? ตามที่ระบุไว้ในข้อกำหนดServletContextเป็นอ็อบเจ็กต์ที่จัดเตรียมเซิร์ฟเล็ตด้วย "มุมมองของแอปพลิเคชัน " ที่พวกเขากำลังทำงานอยู่ บริบทของเซิร์ฟเล็ต อธิบายไว้ ในรายละเอียดเพิ่มเติมในบทที่ 4 ของข้อกำหนดเฉพาะของ Servlet API น่าแปลกที่ Servlet API ในเวอร์ชัน 3.1 ไม่จำเป็นต้องมี web.xml อีกต่อไป ตัวอย่างเช่น คุณสามารถกำหนดเซิร์ฟเล็ตโดยใช้คำอธิบายประกอบ:
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");
}
}
แนะนำในหัวข้อ: " การสัมภาษณ์ Java EE - JEE Servlet API (คำถามและคำตอบ) " ดังนั้นเราจึงมี Servlet - มีหน้าที่รับผิดชอบในการตอบสนองต่อเว็บไคลเอ็นต์ เรามี ServletContainer ที่รับคำขอจากผู้ใช้ จับคู่เส้นทางที่เข้าถึงด้วยเส้นทางไปยังเซิร์ฟเล็ต และหากพบการจับคู่ ให้ดำเนินการ Servlet ดี. สปริง ครอบครอง สถานที่ใดใน ภาพของโลกนี้
สปริงเว็บ MVC
เยี่ยมเลย เรามีเว็บแอปพลิเคชันแล้ว ตอนนี้เราต้องเชื่อมต่อสปริง เราจะทำเช่นนี้ได้อย่างไร? ขั้นแรก คุณต้องทราบวิธีเชื่อมต่อ Spring กับโปรเจ็กต์ของคุณอย่างถูกต้อง ปรากฎว่าก่อนหน้านี้เป็นไปได้ที่จะทำเช่นนี้ตามเอกสารประกอบของ โครงการ แพลตฟอร์ม Springแต่ตอนนี้ “ แพลตฟอร์มจะสิ้นสุดอายุการใช้งานที่รองรับในวันที่ 9 เมษายน 2019 ” นั่นคือไม่แนะนำให้ทำ ใช้มันเพราะว่า อีกไม่นานก็จะไม่ได้รับการสนับสนุนอีกต่อไป ทางออกเดียวคือ " ผู้ใช้แพลตฟอร์มได้รับการสนับสนุนให้เริ่มใช้การจัดการการพึ่งพาของ Spring Boot " ดังนั้นเรามาดู เอกสาร Spring Boot กันดี กว่า ฉันขอชี้แจงว่าเราไม่ได้ใช้ Spring Boot เอง แต่ใช้เฉพาะการจัดการการพึ่งพาจาก Spring Boot นั่นคือโปรเจ็กต์ Spring Boot สามารถให้ความรู้เกี่ยวกับเวอร์ชันของไลบรารีที่จะใช้ (รวมถึง Spring MVC) ที่นั่นเราจะพบ3.2 การใช้การจัดการการพึ่งพาของ Spring Boot ในการแยกไฟล์ . ตามเอกสารประกอบ ให้เพิ่มสิ่งต่อไปนี้ในสคริปต์การสร้าง:plugins {
id 'org.springframework.boot' version '2.0.4.RELEASE' apply false
}
apply plugin: 'io.spring.dependency-management'
และ
dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
}
}
อย่างที่คุณเห็น เราได้ระบุไว้apply false
เช่น เราไม่ได้ใช้ Spring Boot เอง แต่เราใช้การจัดการการพึ่งพาจากที่นั่น การจัดการการขึ้นต่อกันนี้เรียกอีกอย่างว่า BOM - " รายการวัสดุ " ตอนนี้เราพร้อมที่จะเชื่อมต่อโครงการ Spring Web MVC แล้ว Spring Web MVC เป็นส่วนหนึ่งของ โครงการ Spring Frameworkและเราสนใจในส่วน " Web Servlet " มาเพิ่มการพึ่งพาให้กับสคริปต์การสร้าง: compile 'org.springframework:spring-webmvc'
. ดังที่เราเห็น เรากำหนดขอบเขตการคอมไพล์เพราะว่า เว็บเซิร์ฟเวอร์ไม่ได้ให้ Spring แก่เรา โครงการของเราถูกบังคับให้รวมห้องสมุด Spring ไว้ภายในตัวมันเอง ต่อไป เป็นสิ่งสำคัญสำหรับเราที่จะอ่านหัวข้อ " 1.2. DispatcherServlet " ซึ่งมีการกล่าวกันว่าSpring MVCถูกสร้างขึ้นโดยใช้รูปแบบ " Front controller " ซึ่งมีเซิร์ฟเล็ตกลางบางประเภทที่ให้การกำหนดค่าและการมอบหมายไปยังส่วนประกอบอื่น ๆ . ผู้มอบหมายงานสามารถแปลเป็นผู้มอบหมายงานได้ ก่อนอื่นเลย ใน web.xml เราประกาศ:




applicationContext.xml
ที่เราระบุไว้ก่อนหน้านี้ มาดูตัวอย่างจากเอกสารประกอบของ Spring: " 1.10.3. การตรวจจับคลาสและการลงทะเบียนคำจำกัดความ bean โดยอัตโนมัติ "

-
การกำหนดค่าเว็บ เช่น การกำหนดค่าสไตล์ 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(); } }
ตัวอย่างนี้อธิบายไว้ในเอกสาร Spring Framework: " 1.11. MVC Config "
ที่นี่เราลงทะเบียน ViewResolver ซึ่งจะช่วยระบุตำแหน่งของหน้า jsp วิธีที่สองช่วยให้แน่ใจว่าเปิดใช้งาน " เซิร์ฟเล็ตเริ่มต้น " แล้ว
คุณสามารถอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ที่นี่: " ความต้องการและการใช้ default-servlet-handler คืออะไร "
-
ตัวควบคุม HelloController สำหรับอธิบายการแมปคำขอไปยัง JSP เฉพาะ
@Controller public class HelloController { @GetMapping("/hello") public String handle(Model model) { return "hello"; } }
ที่นี่เราได้ใช้คำอธิบายประกอบ @Controller ที่อธิบายไว้ในเอกสารประกอบในบท " 1.4. Annotated Controllers "
/webproject/hello
(โดยที่ /webproject เป็นรูทบริบท) DispatcherServlet จะถูกประมวลผลก่อน เขาในฐานะผู้มอบหมายงานหลักจะพิจารณาว่าเรา /* ตรงกับคำขอปัจจุบัน ซึ่งหมายความว่า DispatcherServlet ต้องทำอะไรบางอย่าง จากนั้นมันจะผ่านการแมปทั้งหมดที่พบ จะเห็นว่ามี HelloController พร้อมวิธีจัดการที่แมปกับ /hello และจะดำเนินการดังกล่าว วิธีนี้จะส่งคืนข้อความ "สวัสดี" ViewResolver จะได้รับข้อความนี้ ซึ่งจะบอกเซิร์ฟเวอร์ว่าจะค้นหาไฟล์ jsp ที่ต้องแสดงต่อไคลเอ็นต์ได้จากที่ไหน ดังนั้นในที่สุดลูกค้าก็จะได้รับเพจอันเป็นที่รักอย่างยิ่ง
GO TO FULL VERSION