CodeGym /Blog Java /Ngẫu nhiên /Tạo một ứng dụng web đơn giản sử dụng servlet và JSP (phầ...
John Squirrels
Mức độ
San Francisco

Tạo một ứng dụng web đơn giản sử dụng servlet và JSP (phần 1)

Xuất bản trong nhóm
Kiến thức cần thiết để hiểu bài viết: Bạn đã ít nhiều tìm hiểu về Java Core và muốn xem xét các công nghệ JavaEElập trình web . Sẽ hợp lý nhất nếu bạn hiện đang nghiên cứu nhiệm vụ Bộ sưu tập Java , giải quyết các chủ đề gần với bài viết.
Tạo một ứng dụng web đơn giản bằng servlet và JSP (phần 1) - 1
Tài liệu này là phần tiếp theo hợp lý của bài viết của tôi Tạo dự án web đơn giản nhất trong IntelliJ Idea Enterprise . Trong bài viết đó, tôi đã trình bày cách tạo một mẫu dự án web đang hoạt động. Lần này tôi sẽ chỉ cho bạn cách tạo một ứng dụng web đơn giản nhưng hoàn toàn hấp dẫn bằng cách sử dụng Java Servlet APIJavaServer Pages API . Ứng dụng của chúng tôi sẽ có một trang chủ với hai liên kết:
  • một liên kết đến một trang để thêm người dùng;
  • một liên kết đến danh sách người dùng.
Như trước đây, tôi sẽ sử dụng IntelliJ Idea Enterprise Edition , Apache Maven (chúng tôi sẽ chỉ kết nối một số phụ thuộc) và Apache Tomcat . Cuối cùng, chúng ta sẽ "làm đẹp" ứng dụng của mình bằng cách sử dụng khung W3.CSS . Chúng tôi sẽ cho rằng bạn đã có một dự án trống mà bây giờ chúng tôi sẽ thêm vào. Nếu không, hãy chạy qua bài viết đầu tiên và tạo một bài viết. Nó sẽ chỉ mất một vài phút :)

Một chút về cấu trúc của ứng dụng trong tương lai của chúng tôi

Trang chủ của chúng tôi (/) sẽ là một trang HTML tĩnh bình thường nhất với tiêu đề và hai liên kết/nút:
  • thêm người dùng mới (điều hướng đến / add );
  • xem danh sách người dùng (điều hướng đến / list ).
Tomcat sẽ bắt các yêu cầu cho các địa chỉ này và gửi chúng đến một trong hai servlet mà chúng tôi sẽ thực hiện (chúng tôi sẽ chỉ định ánh xạ trong web.xml ). Sau đó, các servlet sẽ xử lý các yêu cầu, chuẩn bị dữ liệu (hoặc lưu dữ liệu, nếu chúng tôi đang thêm người dùng) và chuyển quyền kiểm soát tới các tệp JSP thích hợp , sau đó "kết xuất" kết quả. Chúng tôi sẽ lưu trữ dữ liệu trong một danh sách vani đơn giản (Danh sách).

Tạo một trang chủ tĩnh

Nếu bạn index.jsp trong thư mục web của mình, hãy xóa nó. Thay vào đó, hãy tạo một tệp HTML đơn giản có tên là index.html trong thư mục này:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My super project!</title>
</head>
<body>
    <!-- header -->
    <div>
        <h1>Super app!<//h1>
    </div>

    <div>       <!-- content -->
        <div>    <!-- button holder -->
            <button onclick="location.href='/list'">List users<//button>
            <button onclick="location.href='/add'">Add user<//button>
        </div>
    </div>
</body>
</html>
Không có gì phức tạp ở đây. Trong thẻ tiêu đề , chúng tôi chỉ ra tiêu đề của trang của chúng tôi. Trong phần thân trang, chúng ta có hai div chính: tiêu đềnội dung . Div nội dung bao gồm một giá đỡ cho các nút của chúng ta. Và ở đó, chúng tôi có hai nút đưa bạn đến địa chỉ tương ứng bằng một cú nhấp chuột. Bạn có thể chạy dự án và xem nó trông như thế nào bây giờ. Nếu bạn nhấp vào các nút, bạn sẽ nhận được các trang lỗi 404, bởi vì chúng tôi chưa có các trang tương ứng. Nhưng chúng ta có thể nói rằng các nút hoạt động. Lưu ý rằng đây không phải là cách tiếp cận phổ biến nhất: nếu JavaScript bị tắt trong trình duyệt thì các nút này sẽ không hoạt động. Nhưng chúng tôi sẽ cho rằng không ai tắt JavaScript. :) Rõ ràng, bạn có thể thực hiện bằng các liên kết đơn giản, nhưng tôi thích các nút hơn. Bạn có thể làm điều đó tuy nhiên bạn thích. Và đừng lo lắng về thực tế là các ví dụ của tôi sẽ có rất nhiều div . Chúng ta sẽ lấp đầy chúng bằng các kiểu sau và mọi thứ sẽ trông đẹp hơn. :)

Tạo tệp JSP để hiển thị kết quả

Trong cùng một thư mục web , hãy tạo một thư mục nơi chúng tôi sẽ thêm các tệp JSP của mình . Tôi gọi nó là ' lượt xem ', nhưng một lần nữa bạn có thể tùy cơ ứng biến. Trong thư mục này, chúng tôi sẽ tạo hai tệp JSP:
  • add.jsp — một trang để thêm người dùng;
  • list.jsp — trang để hiển thị danh sách người dùng.
Chỉ định tiêu đề trang thích hợp cho họ. Đại loại như " Thêm người dùng mới " và " Danh sách người dùng ", và chúng tôi sẽ để nguyên như vậy.

Tạo hai servlet

Các servlet sẽ nhận và xử lý các yêu cầu mà Tomcat gửi cho chúng. Trong thư mục src/main/java , hãy tạo gói ứng dụng , nơi chúng tôi sẽ đặt mã nguồn của mình. Các gói khác cũng sẽ đến đó. Vì vậy, để ngăn các gói này được tạo bên trong gói khác, chúng tôi sẽ tạo một số lớp trong gói ứng dụng (chúng tôi sẽ xóa nó sau). Bây giờ hãy tạo ba gói khác nhau trong gói ứng dụng :
  • các thực thể — các thực thể của chúng ta (lớp mô tả các đối tượng người dùng) ở đây;
  • mô hình — đây là nơi mô hình của chúng ta hoạt động (chúng ta sẽ nói về điều này sau);
  • servlet — và đây là nơi servlet của chúng ta hoạt động.
Khi bạn đã hoàn thành việc này, bạn có thể bình tĩnh xóa lớp đó khỏi gói ứng dụng (tất nhiên là nếu bạn đã tạo nó). Trong gói servlet , tạo hai lớp:
  • AddServlet — xử lý các yêu cầu được gửi tới / add ;
  • ListServlet — xử lý các yêu cầu được gửi tới / list .

Kết nối các phụ thuộc trong Maven

Tomcat 9 .* triển khai các thông số kỹ thuật cho Servlet 4.0JavaServer Pages 2.3 . Đó là những gì đã nêu trong dòng thứ hai của đoạn đầu tiên trong tài liệu chính thức của Tomcat 9. Điều này có nghĩa là nếu bạn, giống như tôi, sử dụng phiên bản Tomcat này , thì mã bạn sẽ viết và chạy sẽ sử dụng các phiên bản này. Nhưng chúng tôi muốn có các thông số kỹ thuật này trong dự án của mình, để mã của chúng tôi, sử dụng chúng, ít nhất sẽ biên dịch thành công. Và để làm điều này, chúng ta cần tải chúng vào dự án của mình. Đây là nơi Maven đến để giải cứu.

Nguyên tắc chung là: nếu bạn cần kết nối thứ gì đó với dự án của mình bằng Maven:

  • truy cập trang web kho lưu trữ từ Maven;
  • tìm phiên bản yêu cầu của thư viện cần thiết;
  • lấy mã phụ thuộc cần được dán vào tệp pom.xml của bạn;
  • dán! :)
Hãy bắt đầu nào. Đầu tiên, chuẩn bị tệp POM . Đâu đó sau mục /version nhưng trước /project , hãy chèn đoạn sau:

<dependencies>

</dependencies>
Chúng tôi làm điều này để cho biết rằng chúng tôi sẽ liệt kê các thành phần phụ thuộc bắt buộc trong các thẻ này. Bây giờ hãy truy cập mvnrepository.com . Có một trường tìm kiếm ở trên cùng. Để bắt đầu, tìm kiếm ' servlet '. Kết quả đầu tiên, đã được sử dụng hơn bảy nghìn lần, phù hợp với chúng tôi. Hãy nhớ rằng, chúng tôi cần phiên bản 4.0 (dành cho Tomcat 9). Các phiên bản khác có thể phù hợp với các triển khai cũ hơn. Đây là một phiên bản khá mới, vì vậy không có nhiều công dụng. Nhưng chúng ta cần nó. Một trang mở ra nơi bạn có thể lấy mã cho phần phụ thuộc này cho nhiều trình quản lý gói khác nhau hoặc bạn chỉ cần tải xuống. Nhưng vì chúng tôi muốn kết nối nó bằng Maven, nên chúng tôi sẽ chọn mã trên tab Maven. Chúng tôi sao chép và dán vào phần phụ thuộc của tệp POM của chúng tôi. Nếu bạn nhận được thông báo hỏi liệu bạn có muốn bật tự động nhập ở góc dưới bên phải của IDEA hay không, hãy tiếp tục và đồng ý với điều đó. Nếu bạn vô tình từ chối, hãy vào " Settings " và bật tự động nhập thủ công: Settings (Ctrl + Alt + S) -> Build, Execution, Deployment -> Maven -> Importing .và các tệp cấu hình IDEA cho dự án này đồng bộ. Theo nguyên tắc tương tự, chúng ta sẽ tìm và kết nối các Trang JavaServer 2.3 (tìm kiếm "JSP"). Và vì chúng ta đã bắt đầu Maven, nên hãy nói với nó rằng các tệp nguồn của chúng ta tuân theo cú pháp Java 8 và chúng ta cần biên dịch chúng thành mã byte cho phiên bản đó. Sau tất cả các bước này, tệp pom.xml của chúng ta sẽ trông như thế này:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cc.codegym.info.fatfaggy</groupId>
    <artifactId>my-super-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compile.source>1.8</maven.compile.source>
        <maven.compile.target>1.8</maven.compile.target>
    </properties>

    <dependencies>
        <!-- Servlet API 4.0 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JavaServer Pages API 2.3 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

Biến các servlet của chúng ta thành các servlet thực sự

Hiện tại, cặp servlet mà chúng ta đã tạo thực ra là các lớp thông thường. Họ không có bất kỳ chức năng. Nhưng bây giờ chúng tôi đã kết nối API Servlet với dự án của mình và theo đó chúng tôi có thể sử dụng các lớp của nó. Để làm cho các servlet của chúng ta trở nên "thực", tất cả những gì chúng ta cần làm là làm cho chúng kế thừa lớp HttpServlet .

Ánh xạ hoặc đánh dấu

Bây giờ sẽ rất tuyệt nếu bằng cách nào đó nói với Tomcat rằng các yêu cầu về địa chỉ / add được xử lý bởi AddServlet của chúng ta và các yêu cầu về địa chỉ / list được xử lý bởi ListServlet . Quá trình này được gọi là ánh xạ (markup). Điều này được thực hiện trong web.xml bằng cách sử dụng nguyên tắc tương tự:
  • để bắt đầu, hãy mô tả servlet (cung cấp một số tên và chỉ định đường dẫn đến chính lớp đó);
  • sau đó liên kết servlet này với một địa chỉ cụ thể (chỉ định tên của servlet mà chúng tôi vừa cung cấp cho nó và chỉ định địa chỉ mà các yêu cầu sẽ được gửi đến servlet này).
Mô tả servlet:

<servlet>
    <servlet-name>add</servlet-name>
    <servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
Bây giờ liên kết nó với địa chỉ:

<servlet-mapping>
    <servlet-name>add</servlet-name>
    <url-pattern>/add</url-pattern>
</servlet-mapping>
Như bạn có thể thấy, tên servlet giống nhau trong cả hai trường hợp. Kết quả là Tomcat biết rằng nếu nhận được yêu cầu /add, yêu cầu đó phải được gửi tới app.servlets.AddServlet. Chúng tôi làm điều tương tự với servlet thứ hai. Cuối cùng, web.xml của chúng tôi có nội dung xấp xỉ sau:

<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- add servlet -->
    <servlet>
        <servlet-name>add</servlet-name>
        <servlet-class>app.servlets.AddServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>add</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>

    <!-- list servlet -->
    <servlet>
        <servlet-name>list</servlet-name>
        <servlet-class>app.servlets.ListServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>list</servlet-name>
        <url-pattern>/list</url-pattern>
    </servlet-mapping>
</web-app>
Nhân tiện, chúng tôi không tạo đánh dấu cho trang chủ (/). Thực tế là chúng ta không cần nó trong trường hợp này. Trang chủ của chúng tôi là một tệp HTML đơn giản chỉ hiển thị hai nút. Nó không có nội dung động, vì vậy chúng tôi không cần tạo một servlet riêng cho các yêu cầu từ / sẽ không làm gì ngoài việc chuyển tiếp thực thi tới một số JSP (cũng sẽ phải được tạo) để vẽ hai nút cho chúng tôi. Chúng tôi không cần cái này. Một trang tĩnh phù hợp với chúng tôi. Khi Tomcat nhận được yêu cầu, nó sẽ kiểm tra xem có một servlet nào có thể xử lý yêu cầu cho địa chỉ đó hay không và sau đó sẽ thấy rằng địa chỉ này thực sự đã chứa tệp HTML sẵn sàng, mà nó sẽ phục vụ. Chúng tôi có thể chạy lại ứng dụng của mình (khởi động lại máy chủ hoặc triển khai lại nó—bất cứ điều gì bạn thích) và đảm bảo rằng trang chủ được hiển thị, không có gì bị hỏng và quá trình chuyển đổi xảy ra khi chúng tôi nhấp vào các nút (mặc dù chúng tôi lại gặp lỗi). Nhân tiện, trong khi trước đây chúng tôi gặp lỗi 404 thì bây giờ chúng tôi gặp lỗi 405. Điều đó có nghĩa là ánh xạ đã hoạt động và các servlet đã được tìm thấy, nhưng chúng không có phương pháp phù hợp để xử lý yêu cầu.

Lạc đề ngắn: điều gì xảy ra "dưới mui xe"?

Bạn có thể đã nghĩ về cách ứng dụng của chúng tôi hoạt động trong Tomcat. Điều gì xảy ra trong đó? Và phương thức main() ở đâu? Ngay khi bạn truy cập localhost:8080 trong trình duyệt của mình, trình duyệt sẽ gửi yêu cầu đến địa chỉ này bằng giao thức HTTP. Tôi hy vọng bạn đã biết rằng có nhiều loại yêu cầu khác nhau và phổ biến nhất là GET và POST. Mỗi yêu cầu nên được trả lời. Yêu cầu GET sẽ nhận được phản hồi của mã HTML sẵn sàng sử dụng, được trả lại cho trình duyệt. Sau đó, trình duyệt sẽ thay thế mã sẽ tất cả các chữ cái, nút và biểu mẫu đẹp. Yêu cầu POST thú vị hơn một chút vì nó cũng mang một số thông tin. Ví dụ: giả sử bạn nhập thông tin đăng nhập vào biểu mẫu đăng ký hoặc đăng nhập trên trang web và nhấp vào "Gửi". Điều này khiến một yêu cầu POST với thông tin cá nhân của bạn được gửi đến máy chủ. Máy chủ nhận thông tin này, xử lý và trả về một số phản hồi (ví dụ: trang HTML có hồ sơ của bạn). Sự khác biệt chính giữa chúng là các yêu cầu GET chỉ được sử dụng để truy xuất dữ liệu từ máy chủ, trong khi các yêu cầu POST mang một số thông tin (và dữ liệu trên máy chủ có thể thay đổi). Ví dụ: khi bạn tải ảnh của mình lên máy chủ, nó sẽ được chuyển đến đó trong một yêu cầu POST và máy chủ sẽ thêm nó vào cơ sở dữ liệu, tức là có một thay đổi xảy ra. Bây giờ trở lại Tomcat. Khi nhận được yêu cầu từ khách hàng, nó sẽ xem địa chỉ. Nó kiểm tra xem có một servlet phù hợp để xử lý các yêu cầu cho địa chỉ đó hay không (hoặc một tài nguyên có sẵn có thể được trả lại ngay lập tức). Nếu nó không tìm thấy một cái gì đó để trở lại, sau đó nó phản hồi với lỗi 404 thay vì trang HTML. Nhưng nếu nó tìm thấy một servlet phù hợp đang "ngồi" tại địa chỉ đó, thì nó sẽ xem xét loại yêu cầu (GET, POST hoặc thứ gì đó khác) và hỏi servlet xem nó có phương thức nào có thể xử lý loại truy vấn này không. Nếu servlet nói rằng nó không biết cách xử lý loại này, thìTomcat trả về mã 405. Và đây chỉ là những gì đã xảy ra trong dự án của chúng tôi. Nhưng nếu tìm thấy một servlet phù hợp và nó có một phương thức phù hợp, thì Tomcat sẽ tạo một đối tượng servlet, khởi động nó trên một luồng mới(cho phép nó tự chạy) và Tomcat tiếp tục công việc của chính nó, chấp nhận và gửi yêu cầu. Ngoài ra, Tomcat tạo thêm hai đối tượng: một HttpServletRequest (tôi sẽ gọi tắt là "yêu cầu") và một HttpServletResponse (tôi sẽ gọi là "phản hồi"). Nó đặt tất cả dữ liệu nhận được từ yêu cầu của khách hàng vào đối tượng đầu tiên, vì vậy tất cả dữ liệu đó có thể được trích xuất từ ​​​​đối tượng đó. Và sau tất cả những điều này, nó chuyển hai đối tượng này sang phương thức thích hợp của servlet đã được bắt đầu trên một luồng riêng biệt. Ngay sau khi servlet hoàn thành công việc của nó và có một phản hồi sẵn sàng để gửi tới máy khách, nó vẫy cờ về phía Tomcat, nói rằng "Tôi đã hoàn thành. Mọi thứ đã sẵn sàng". Tomcat nhận phản hồi và gửi nó cho khách hàng. Điều này cho phép Tomcat nhận yêu cầu và gửi phản hồi, mà không bị phân tâm và tất cả công việc được thực hiện bởi các servlet chạy trên các luồng riêng biệt. Điều đó có nghĩa là khi chúng tôi viết mã servlet, chúng tôi xác định công việc nào sẽ được thực hiện. Và bạn có thể nghĩ phương thức main() được đặt bên trong chính Tomcat (vâng, nó được viết bằng Java) và khi chúng tôi "khởi chạy" Tomcat, phương thức main() được bắt đầu. Tạo một ứng dụng web đơn giản bằng servlet và JSP (phần 1) - 2

Sử dụng servlet để bắt các phương thức GET và gửi phản hồi cực kỳ đơn giản

Hiện tại, các servlet của chúng tôi không có phương thức phù hợp (GET), vì vậy Tomcat trả về lỗi 405. Hãy tạo ra chúng! Lớp HttpServlet, mà các servlet của chúng ta kế thừa, khai báo các phương thức khác nhau. Để gán mã cụ thể cho các phương thức, chúng ta chỉ cần ghi đè lên chúng. Trong trường hợp này, chúng ta cần ghi đè doGet()phương thức trong cả hai servlet.

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}
Như bạn có thể thấy, phương thức này nhận hai đối số: req (yêu cầu) và resp (phản hồi). Đây chính là những đối tượng mà Tomcat tạo ra và điền vào cho chúng ta khi nó gọi phương thức thích hợp trong servlet. Để bắt đầu, chúng tôi sẽ tạo các phản hồi đơn giản nhất. Để làm điều này, chúng ta sẽ lấy đối tượng resp và lấy đối tượng PrintWriter từ nó. Loại đối tượng này được sử dụng để soạn phản hồi. Chúng tôi sẽ sử dụng nó để xuất một chuỗi đơn giản.

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter();
    writer.println("GET method from AddServlet");
}
Chúng tôi sẽ làm điều gì đó tương tự trong ListServlet, sau đó chúng tôi sẽ khởi động lại máy chủ của mình. Như bạn có thể thấy, mọi thứ đều hoạt động! Khi bạn nhấp vào các nút, bạn sẽ nhận được các trang có văn bản mà chúng tôi đã "viết" bằng PrintWriter. Tuy nhiên, các tệp JSP mà chúng tôi đã chuẩn bị để tạo các trang có phản hồi không được sử dụng. Đó đơn giản là vì chúng không bao giờ được thực thi. servlet của chúng ta tự tạo phản hồi và chạy xong, báo hiệu cho Tomcat rằng nó đã sẵn sàng phản hồi cho máy khách. Tomcat chỉ nhận phản hồi và gửi lại cho khách hàng. Hãy chuyển quyền kiểm soát từ các servlet sang các tệp JSP. Chúng tôi sẽ thay đổi mã của các phương thức của chúng tôi như sau:
  • chúng tôi lấy đối tượng điều phối yêu cầu từ đối tượng yêu cầu và chuyển cho nó địa chỉ của trang JSP mà chúng tôi muốn chuyển quyền kiểm soát tới;
  • chúng tôi sử dụng đối tượng này để chuyển điều khiển đến trang JSP đã chỉ định, không quên chuyển các đối tượng yêu cầu và phản hồi mà chúng tôi nhận được từ Tomcat.

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
    requestDispatcher.forward(req, resp);
}
Trong thẻ nội dung của các trang JSP, bạn có thể thêm một cái gì đó để chúng tôi có thể thấy rõ trang nào đang được hiển thị. Khi bạn đã hoàn thành việc đó, hãy khởi động lại máy chủ và kiểm tra. Chúng tôi nhấp vào các nút trên trang chính và các trang mở ra, điều đó có nghĩa là các yêu cầu đang được gửi đến các servlet. Sau đó, điều khiển được chuyển đến các trang JSP, hiện đang được hiển thị. Đó là tất cả cho bây giờ. Trong phần tiếp theo của bài viết này, chúng ta sẽ nghiên cứu chức năng của ứng dụng.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION