JSP: Ngôn ngữ biểu thức hợp nhất


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Tính năng mới chính của JSP 2.1 là ngôn ngữ biểu hiện thống nhất (unified EL), đại diện cho sự kết hợp của ngôn ngữ biểu hiện được cung cấp bởi JSP 2.0 và ngôn ngữ biểu hiện được tạo cho công nghệ JavaServer Faces phiên bản 1.0.

Ngôn ngữ biểu hiện được giới thiệu trong JSP 2.0 cho phép các tác giả trang sử dụng các biểu thức đơn giản để tự động đọc dữ liệu từ các thành phần JavaBeans. Ví dụ: thuộc tính test của thẻ điều kiện sau đây được cung cấp với biểu thức EL để so sánh số lượng các mục trong session giỏ hàng có tên là cart với 0.

<c:if test="${sessionScope.cart.numberOfItems > 0}">
  ...
</c:if>

Như đã giải thích trong bài viết Vòng đời của trang JSP, JSP hỗ trợ một chu kỳ yêu cầu/đáp ứng, trong đó một trang được thực hiện và thẻ HTML được hiển thị ngay lập tức. Do đó, ngôn ngữ biểu hiện rất đơn giản, nó chỉ việc đọc nội dung được cung cấp bởi JSP 2.0 phù hợp với nhu cầu của các ứng dụng JSP.

Mặt khác, công nghệ JavaServer Faces có chu kỳ đa năng được thiết kế để hỗ trợ mô hình thành phần UI phức tạp của nó, cho phép chuyển đổi và xác nhận dữ liệu thành phần, truyền dữ liệu thành các đối tượng và xử lý sự kiện thành phần. Để tạo thuận lợi cho các chức năng này, công nghệ JavaServer Faces đã giới thiệu ngôn ngữ biểu hiện riêng của mình bao gồm các chức năng sau:

  • Đánh giá các biểu thức

  • Khả năng thiết lập dữ liệu cũng như lấy dữ liệu

  • Khả năng gọi phương thức

Hai ngôn ngữ biểu hiện này đã được hợp nhất vì một vài lý do. Một trong những lý do là do các tác giả trang có thể kết hợp nội dung JSP với các thẻ Faces của JavaServer mà không phải lo lắng về những xung đột gây ra bởi các chu kỳ cuộc sống khác nhau mà các công nghệ này hỗ trợ. Một lý do khác là do các công nghệ dựa trên JSP khác có thể sử dụng các tính năng bổ sung tương tự như cách công nghệ JavaServer Faces sử dụng chúng. Trên thực tế, mặc dù các thẻ JSP tiêu chuẩn và nội dung tĩnh vẫn tiếp tục sử dụng chỉ những tính năng có trong JSP 2.0, thì các tác giả của các thẻ tùy chỉnh JSP có thể tạo các thẻ sử dụng bộ tính năng mới trong ngôn ngữ biểu thức hợp nhất.

Tóm lại, ngôn ngữ biểu thức mới, hợp nhất cho phép các tác giả trang sử dụng các biểu thức đơn giản để thực hiện các tác vụ sau:

  • Tự động đọc dữ liệu ứng dụng được lưu trữ trong các thành phần JavaBeans, các cấu trúc dữ liệu khác nhau và các đối tượng tiềm ẩn

  • Tự động viết dữ liệu, chẳng hạn như người dùng nhập vào các biểu mẫu, thành các thành phần JavaBeans

  • Gọi các phương thức static và public tùy ý

  • Tự động thực hiện các phép tính số học

EL hợp nhất cũng cho phép các nhà phát triển thẻ tùy chỉnh chỉ định những kiểu biểu thức sau tùy thuộc vào thuộc tính thẻ tùy chỉnh được chấp nhận hay không:

  • Các biểu thức lượng giá trực tiếp hoặc các biểu thức lượng giá gián tiếp. Một biểu thức lượng giá trực tiếp được đánh giá bởi công cụ JSP. Một biểu thức lượng giá gián tiếp có thể được đánh giá sau đó bởi công nghệ cơ bản sử dụng ngôn ngữ biểu thức.

  • Biểu thức giá trị hoặc biểu thức phương thức. Một biểu thức giá trị sẽ tham chiếu đến dữ liệu, trong khi một biểu thức phương thức sẽ gọi một phương thức khác.

  • Biểu thức Rvalue hoặc biểu thức Lvalue . Một biểu thức rvalue chỉ có thể đọc một giá trị, trong khi một biểu thức lvalue có thể đọc và ghi giá trị đó cho một đối tượng bên ngoài.

Cuối cùng, EL hợp nhất cũng cung cấp một API có thể thêm vào được để giải quyết các biểu thức sao cho các nhà phát triển ứng dụng có thể tự giải quyết để có thể xử lý các biểu thức chưa được hỗ trợ bởi EL hợp nhất.

Bài viết này cung cấp cái nhìn tổng quan về các tính năng của ngôn ngữ biểu thức thống nhất bằng cách giải thích các chủ đề sau:

Cú pháp lượng giá trực tiếp và gián tiếp

EL hợp nhất hỗ trợ cả cú pháp lượng giá trực tiếp và gián tiếp. Lượng giá trực tiếp có nghĩa là công cụ JSP đánh giá biểu thức và trả về kết quả ngay khi trang được hiển thị lần đầu. Lượng giá gián tiếp có nghĩa là công nghệ sử dụng ngôn ngữ biểu thức có thể sử dụng máy móc của chính nó để đánh giá biểu thức sau này trong suốt vòng đời của trang bất cứ lúc nào.

Những biểu thức được lượng giá trực tiếp sẽ sử dụng cú pháp ${}, được giới thiệu với ngôn ngữ biểu thức JSP 2.0. Biểu thức được lượng giá sẽ được gián tiếp cú pháp #{}, được giới thiệu bởi công nghệ JavaServer Faces.

Do chu kỳ sống được chia làm nhiều pha, nên công nghệ JavaServer Faces sử dụng các biểu thức lượng giá gián tiếp. Trong suốt chu kỳ thì các sự kiện của thành phần sẽ được xử lý, dữ liệu được xác nhận và các nhiệm vụ khác được thực hiện, tất cả được thực hiện theo một thứ tự nhất định. Do đó, nó phải gián tiếp lượng giá các biểu thức cho đến khi đạt đến điểm thích hợp trong chu trình sống.

Các công nghệ khác sử dụng EL hợp nhất có thể có các lý do khác nhau để sử dụng các biểu thức gián tiếp.

Lượng giá trực tiếp

Tất cả các biểu thức sử dụng cú pháp ${} sẽ được lượng giá trực tiếp. Các biểu thức này chỉ có thể được sử dụng trong văn bản mẫu hoặc như giá trị của thuộc tính thẻ JSP có thể chấp nhận các biểu thức runtime.

Ví dụ sau cho thấy một thẻ trong đó thuộc tính value tham chiếu đến một biểu thức lượng giá trực tiếp sẽ lấy tổng giá từ session có tên cart:

<fmt:formatNumber value="${sessionScope.cart.total}"/>

Công cụ JSP sẽ lượng giá biểu thức ${sessionScope.cart.total}, chuyển đổi nó và chuyển giá trị trả về cho trình xử lý thẻ.

Các biểu thức lượng giá trực tiếp luôn là các biểu thức giá trị read-only. Các biểu thức ở trên chỉ có thể nhận được tổng giá từ session, nó không thể thiết lập được tổng giá.

Lượng giá gián tiếp

Biểu thức lượng giá gián tiếp có dạng {#expr} và có thể được đánh giá ở các giai đoạn khác của vòng đời của trang như đã được định nghĩa bởi bất kỳ công nghệ nào đang sử dụng biểu thức. Trong trường hợp công nghệ là JavaServer Faces, thì bộ điều khiển của nó có thể đánh giá biểu thức ở các giai đoạn khác nhau của vòng đời tùy thuộc vào cách biểu thức được sử dụng trong trang.

Ví dụ sau cho thấy một thẻ InputText của JavaServer Faces, nó đại diện cho một thành phần trường văn bản mà người dùng có thể nhập vào một giá trị. Thuộc tính value của thẻ inputText tham chiếu một biểu thức lượng giá gián tiếp sẽ trỏ đến thuộc tính name của bean customer.

<h:inputText id="name" value="#{customer.name}" />

Đối với yêu cầu ban đầu của trang có chứa thẻ này, việc triển khai ứng dụng JavaServer Faces sẽ lượng giá biểu thức #{customer.name} trong giai đoạn phản hồi của vòng đời. Trong giai đoạn này, biểu thức chỉ truy cập vào giá trị của name từ bean customer như được thực hiện theo hướng lượng giá trực tiếp.

Đối với việc khôi phục, việc triển khai ứng dụng JavaServer Faces sẽ lượng giá biểu thức ở các giai đoạn khác nhau của vòng đời, trong thời gian đó giá trị được lấy ra từ yêu cầu, được hợp thức hóa và được truyền đến bean customer.

Như thể hiện trong ví dụ, các biểu thức lượng giá gián tiếp có thể là các biểu thức giá trị và vì vậy có thể được dùng để đọc và ghi dữ liệu. Chúng cũng có thể là các biểu thức phương thức. Các biểu thức giá trị (bao gồm cả trực tiếp và gián tiếp) và các biểu thức phương thức được giải thích trong bài học tiếp theo.

Biểu thức giá trị và biểu thức phương thức

Các EL hợp nhất định nghĩa hai loại biểu thức: biểu thức giá trị và biểu thức phương thức. Biểu thức giá trị có thể lấy hoặc thiết lập một giá trị, còn biểu thức phương thức sẽ tham chiếu đến các phương thức mà có thể được gọi và có thể trả về một giá trị.

Biểu thức giá trị

Các biểu thức giá trị có thể được phân loại thành các biểu thức rvalue và lvalue. Biểu thức Rvalue là biểu thức có thể đọc dữ liệu, nhưng không thể ghi nó. Biểu thức Lvalue có thể đọc và ghi dữ liệu.

Tất cả các biểu thức được lượng giá trực tiếp sẽ sử dụng bộ phân cách ${} và luôn biểu diễn rvalue. Các biểu thức lượng giá gián tiếp lại sử dụng bộ phân cách #{} và có thể hoạt động dưới dạng biểu thức rvalue và lvalue. Xét hai biểu thức giá trị sau đây:

<taglib:tag value="${customer.name}" />
<taglib:tag value="#{customer.name}" />

Biểu thức trên sử dụng cú pháp lượng giá trực tiếp, trong khi biểu thức dưới sử dụng cú pháp lượng giá gián tiếp. Biểu thức trên truy cập vào thuộc tính name, lấy giá trị, và giá trị được thêm vào response và hiển thị trên trang. Điều tương tự có thể xảy ra với biểu thức thứ hai. Tuy nhiên, trình xử lý thẻ có thể trì hoãn việc đánh giá biểu thức này sau một thời gian trong chu trình sống của trang, nếu công nghệ sử dụng thẻ này cho phép nó.

Trong trường hợp công nghệ JavaServer Faces, biểu thức của thẻ thứ hai được lượng giá trực tiếp trong quán trình khởi tạo request cho trang. Trong trường hợp này, biểu thức này hoạt động như một biểu thức rvalue. Trong quá trình khôi phục lại, biểu thức này có thể được sử dụng để đặt giá trị của thuộc tính name với đầu vào của người dùng. Trong trường hợp này, biểu thức hoạt động như một biểu thức lvalue.

Tham chiếu đối tượng sử dụng biểu thức giá trị

Cả hai biểu thức rvalue và lvalue đều có thể tham chiếu các đối tượng sau đây bao gồm cả thuộc tính và trường của chúng:

  • Các thành phần JavaBeans

  • Collections

  • Kiểu liệt kê củaJava SE

  • Các đối tượng ngầm định

Xem phần Các đối tượng ngầm định để biết thêm chi tiết về các đối tượng ngầm định có sẵn với công nghệ JSP.

Để tham khảo các đối tượng này, bạn viết một biểu thức bằng cách sử dụng một tên biến mà bạn đã tạo đối tượng. Biểu thức sau biểu diễn một thành phần JavaBeans được gọi là customer.

${customer}

Bộ chứa web sẽ lượng giá một biến xuất hiện trong một biểu thức bằng cách tra cứu giá trị của nó theo hành vi của PageContext.findAttribute(String), trong đó đối số String là tên của biến. Ví dụ: khi lượng giá biểu thức ${customer}, bộ chứa sẽ tìm kiếm customer trong trang, trong request, trong session, phạm vi ứng dụng và sẽ trả về giá trị của nó. Nếu không tìm thấy customer thì sẽ trả về null. Một biến phù hợp với một trong những đối tượng ngầm định được mô tả trong phần Các đối tượng ngầm định sẽ trả về đối tượng ngầm định đó thay vì giá trị của biến.

Bạn có thể thay đổi cách các biến được giải quyết bằng một trình xử lý EL tùy chỉnh, đây là một tính năng mới của EL hợp nhất. Ví dụ: bạn có thể cung cấp một trình xử lý EL để chặn các đối tượng có tên customer, do đó ${customer} sẽ trả về giá trị trong bộ xử lý EL. Tuy nhiên, bạn không thể ghi đè các đối tượng ngầm định theo cách này. Xem phần Trình xử lý EL để biết thêm thông tin về trình xử lý EL.

Bạn có thể đặt tên biến customer khi bạn khai báo bean. Xem phần Tạo và sử dụng hợp phần JavaBeans để biết thông tin về cách khai báo thành phần JavaBeans để sử dụng trong các trang JSP của bạn.

Để khai báo các bean trong các ứng dụng JavaServer Faces, bạn sử dụng cơ sở bean được quản lý.

Khi tham chiếu một hằng số enum với một biểu thức thì bạn sử dụng một hằng String. Ví dụ, hãy xem lớp Enum sau:

public enum Suit {hearts, spades, diamonds, clubs}

Để tham chiếu hằng SuitSuit.hearts với một biểu thức, bạn sử dụng hằng String là "hearts". Tùy thuộc vào ngữ cảnh mà hằng String được chuyển đổi thành hằng số enum tự động. Ví dụ, trong biểu thức sau đây trong đó mySuit là một thể hiện của Suit"hearts" trước tiên được chuyển thành Suit.hearts trước khi nó được so sánh với thể hiện.

${mySuit == "hearts"}

Tham chiếu đến các thuộc tính đối tượng sử dụng các biểu thức giá trị

Để tham chiếu các thuộc tính của một bean hoặc một thể hiện Enum, các thành phần của một collection, hoặc các thuộc tính của một đối tượng tiềm ẩn, thì bạn sử dụng ký hiệu . (dấu chấm) hoặc [], tương tự như ký hiệu được sử dụng bởi ECMAScript.

Vì vậy, nếu bạn muốn tham chiếu thuộc tính name của bean customer thì bạn có thể sử dụng biểu thức ${customer.name} hoặc biểu thức ${customer["name"]} . Phần bên trong dấu ngoặc vuông là một hằng String là tên thuộc tính để tham chiếu.

Bạn có thể sử dụng dấu nháy kép hoặc dấu nháy đơn cho hằng String. Bạn cũng có thể kết hợp ký hiệu [] và . như được thể hiện sau đây:

${customer.address["street"]}

Thuộc tính của một enum cũng có thể được tham chiếu theo cách này. Tuy nhiên, như với các thuộc tính thành phần của JavaBeans, thuộc tính của lớp Enum phải tuân theo các quy ước của thành phần JavaBeans. Điều này có nghĩa là một thuộc tính phải có ít nhất một phương thức accessor gọi là get<Property> (trong đó <Property> là tên thuộc tính) để một biểu thức có thể tham chiếu nó.

Ví dụ: giả sử bạn có một lớp Enum bao hàm tên của các hành tinh trong thiên hà của chúng ta và trong đó có một phương thức để có được khối lượng của một hành tinh. Bạn có thể sử dụng biểu thức sau để tham chiếu phương thức getMass của lớp Enum Planet :

${myPlanet.mass}

Nếu bạn đang truy cập vào một mục trong một mảng hoặc một danh sách, bạn phải sử dụng một giá trị văn bản có thể bị buộc phải là int hoặc ký hiệu [] với một int và không có dấu ngoặc kép. Trong các ví dụ sau tất cả có thể giải quyết cùng một mục trong một danh sách hoặc mảng, giả sử rằng socks có thể bị buộc phải có kiểu int:

  • ${customer.orders[1]}

  • ${customer.orders.socks}

Ngược lại, mỗi mục trong một Map có thể được truy cập bằng cách sử dụng một chuỗi khóa literal, không bắt buộc phải cưỡng chế:

${customer.orders["socks"]}

Một biểu thức rvalue cũng tham chiếu trực tiếp tới các giá trị không phải là các đối tượng, chẳng hạn như kết quả của các phép toán số học và các giá trị văn bản, như thể hiện trong các ví dụ sau:

  • ${"literal"}

  • ${customer.age + 20}

  • ${true}

  • ${57}

Ngôn ngữ biểu thức hợp nhất định nghĩa các chữ cái sau:

  • Boolean: đúng và sai

  • Integer: như trong Java

  • Float: như trong Java

  • String: với dấu nháy đơn và đôi; " Được escape là \"' được escape là \', và \ được escape là \\

  • Null: null

Bạn cũng có thể viết các biểu thức để thực hiện các hoạt động trên một hằng số enum. Ví dụ, hãy xem xét lớp Enum sau:

public enum Suit {club, diamond, heart, spade }

Sau khi khai báo một hằng enum gọi là mySuit, bạn có thể viết biểu thức sau đây để kiểm tra nếu mySuit là spade:

${mySuit == "spade"}

Khi cơ chế giải quyết EL giải quyết biểu thức này, nó sẽ gọi phương thức valueOf của lớp Enum với lớp Suit và kiểu spade, như được hiển thị ở đây:

mySuit.valueOf(Suit.class, "spade"}

Nơi biểu thức giá trị có thể được sử dụng

Các biểu thức giá trị sử dụng bộ phân tách ${} có thể được sử dụng ở những nơi sau:

  • Trong văn bản tĩnh

  • Trong bất kỳ thuộc tính thẻ chuẩn hoặc tùy chỉnh nào có thể chấp nhận một biểu thức

Giá trị của một biểu thức trong văn bản tĩnh được tính toán và chèn vào đầu ra hiện thời. Dưới đây là ví dụ về một biểu thức được nhúng trong văn bản tĩnh:

<some:tag>
    some text ${expr} some text
</some:tag>

Nếu văn bản tĩnh xuất hiện trong thân của thẻ, thì lưu ý rằng một biểu thức sẽ không được lượng giá nếu phần thân không được khai báo là tagdependent.

Các biểu thức Lvalue chỉ có thể được sử dụng trong các thuộc tính thẻ có thể chấp nhận các biểu thức lvalue.

Có ba cách để đặt giá trị thuộc tính thẻ sử dụng biểu thức rvalue hoặc lvalue:

  • Với một cấu trúc biểu thức đơn:

    <some:tag value="${expr}"/>
    <another:tag value="#{expr}"/>

    Các biểu thức này được lượng giá và kết quả là bắt buộc đối với loại thuộc tính mong muốn.

  • Với một hoặc nhiều biểu thức phân cách nhau hoặc bao quanh bởi văn bản:

    <some:tag value="some${expr}${expr}text${expr}"/>
    <another:tag value="some#{expr}#{expr}text#{expr}"/>

    Những loại biểu thức này được gọi là các biểu thức tổng hợp. Chúng được lượng giá từ trái sang phải. Mỗi biểu thức được nhúng trong biểu thức tổng hợp buộc phải là một String và sau đó được nối với bất kỳ văn bản can thiệp nào. Chuỗi String do đó được ép kiểu đối với kiểu dự kiến ​​của thuộc tính.

  • Nếu chỉ có văn bản:

    <some:tag value="sometext"/>

    Biểu thức này được gọi là một biểu thức literal. Trong trường hợp này, giá trị String của thuộc tính được ép sang kiểu mong muốn của thuộc tính. Biểu thức giá trị literal có các quy tắc cú pháp đặc biệt, khi thuộc tính của thẻ có kiểu enum, thì biểu thức mà thuộc tính sử dụng phải là một biểu thức literal. Ví dụ, thuộc tính của thẻ có thể sử dụng cụm từ "hearts" để chỉ Suit.hearts. Literal được ép sang kiểu Suit và thuộc tính sẽ lấy giá trị Suit.hearts.

Tất cả các biểu thức được sử dụng để thiết lập giá trị thuộc tính được lượng giá trong ngữ cảnh của một kiểu dự kiến. Nếu kết quả của việc đánh giá biểu thức không phù hợp với kiểu mong muốn một cách chính xác thì một chuyển đổi kiểu sẽ được thực thi. Ví dụ: biểu thức ${1.2E4} được cung cấp khi giá trị của thuộc tính của kiểu float sẽ dẫn đến chuyển đổi sau:

Float.valueOf("1.2E4").floatValue()

Phương thức Biểu thức

Một tính năng khác của ngôn ngữ biểu thức hợp nhất là sự hỗ trợ của nó đối với các biểu thức phương thức gián tiếp. Một biểu thức phương thức được sử dụng để gọi một phương thức public tùy ý, có thể trả lại kết quả. Một tính năng tương tự của EL hợp nhất là các hàm. Cách biểu hiện của phương thức có một số điểm khác với các chức năng.

Biểu thức phương thức chủ yếu mang lại lợi ích cho công nghệ JavaServer Faces, nhưng chúng cũng có sẵn cho bất kỳ công nghệ nào có thể hỗ trợ ngôn ngữ biểu thức hợp nhất. Chúng ta hãy cùng xem JavaServer Faces sử dụng công nghệ biểu thức phương thức như thế nào.

Trong công nghệ JavaServer Faces, thẻ thành phần đại diện cho một thành phần UI trên một trang. Thẻ thành phần sử dụng các biểu thức phương thức để gọi các phương thức thực hiện một số quá trình xử lý cho thành phần. Các phương thức này là cần thiết để xử lý các sự kiện mà các thành phần tạo ra và xác nhận dữ liệu thành phần, như được thể hiện trong ví dụ sau:

<h:form>
    <h:inputText
         id="name"
        value="#{customer.name}"
        validator="#{customer.validateName}"/>
    <h:commandButton
        id="submit"
        action="#{customer.submit}" />
</h:form>

Thẻ inputText hiển thị thành phần UIInput như một trường văn bản. Thuộc tính validator của thẻ inputText này sẽ tham chiếu đến một phương thức gọi là validateName, trong bean được gọi là customer. TLD để định nghĩa thẻ inputText sẽ xác định những dấu hiệu mà phương thức được đề cập đến bởi các thuộc tính validator phải có. Điều tương tự cũng đúng với phương thức customer.submit được tham chiếu bởi thuộc tính action của thẻ commandButton. TLD xác định rằng phương thức submit phải trả về thể hiện Object xác định trang nào để điều hướng tới sau khi nút được biểu thị bởi thẻ commandButton được nhấp.

Phương thức validation được gọi trong giai đoạn quá trình xác nhận của chu kỳ cuộc sống, trong khi phương thức submit được gọi trong giai đoạn gọi ứng dụng của vòng đời. Bởi vì một phương thức có thể được gọi trong các giai đoạn khác nhau của vòng đời, nên các biểu thức phương thức phải luôn luôn sử dụng cú pháp lượng giá gián tiếp.

Tương tự như biểu thức lvalue, biểu thức phương thức có thể sử dụng các toán tử [] và . . Ví dụ, #{object.method} tương đương với #{object["method"]}. Các chữ bên trong [] được ép kiểu đối với String và được sử dụng để tìm tên của phương thức phù hợp với nó. Một khi phương thức được tìm thấy thì nó được gọi hoặc thông tin về phương thức sẽ được trả về.

Biểu thức phương thức chỉ có thể được sử dụng trong các thuộc tính thẻ và chỉ bằng các cách sau:

  • Với một cấu trúc biểu thức đơn giản, trong đó bean tham chiếu đến một thành phần JavaBeans và method tham chiếu đến một phương thức của thành phần JavaBeans:

    <Some: tag value = "# {bean.method}" />

    Biểu thức được lượng giá là một biểu thức phương thức, được truyền cho trình xử lý thẻ. Phương thức được biểu diễn bởi biểu thức phương thức có thể được gọi sau.

  • Chỉ với văn bản:

    <some:tag value="sometext"/>

    Các biểu thức phương thức hỗ trợ các ký tự chủ yếu để hỗ trợ các thuộc tính action trong công nghệ JavaServer Faces. Khi phương thức được tham chiếu bởi biểu thức phương thức này được gọi thì nó sẽ trả về hằng String, sau đó sẽ được ép sang kiểu trả về dự kiến, như được định nghĩa trong TLD của thẻ.

Định nghĩa một kiểu thuộc tính thẻ

Như đã giải thích trong phần trước, tất cả các loại biểu thức đều có thể được sử dụng trong các thuộc tính thẻ. Loại biểu thức nào và cách biểu thức đó được đánh giá như thế nào (trực tiếp) được xác định bởi thuộc tính type của định nghĩa của thẻ trong tệp TLD (xem Thẻ Descriptors Thư viện ) xác định thẻ.

Nếu bạn định tạo các thẻ tùy chỉnh (xem Chương 8, Thẻ tùy chỉnh trong các trang JSP ), bạn cần chỉ định cho mỗi thẻ trong TLD loại biểu thức nào nó chấp nhận. Bảng dưới đây cho thấy ba loại thuộc tính thẻ chấp nhận các biểu thức EL và cho ví dụ về các biểu thức mà chúng chấp nhận và các định nghĩa kiểu của các thuộc tính phải được thêm vào TLD. Bạn không thể sử dụng cú pháp #{} cho một thuộc tính động, nghĩa là một thuộc tính chấp nhận các giá trị được tính tự động trong thời gian chạy. Phần 2.3.2 của đặc tả JavaServer Pages 2.1 đề cập đến các thuộc tính này. Bạn cũng không thể sử dụng cú pháp ${} cho thuộc tính gián tiếp.

Loại thuộc tính

Biểu thức ví dụ

Định nghĩa thuộc tính kiểu

động

"literal"

<rtexprvalue>true</rtexprvalue>

${literal}

<rtexprvalue>true</rtexprvalue>

giá trị gián tiếp

"literal"

<deferred-value>
   <type>java.lang.String</type>
</deferred-value>

#{customer.age}

<deferred-value>
   <type>int</type>
</deferred-value>

phương thức gián tiếp

"literal"

<deferred-method>
   <method-signature>
      java.lang.String submit()
   </method-signature>
<deferred-method>

#{customer.calcTotal}

<deferred-method>
   <method-signature>
      double calcTotal(int, double)
   </method-signature>
</deferred-method>

Các định nghĩa của các thuộc tính thẻ chấp nhận các biểu thức EL

Ngoài các loại thuộc tính thẻ được hiển thị trong bảng trên, bạn cũng có thể xác định một thuộc tính để chấp nhận cả biểu thức động và gián tiếp. Trong trường hợp này, định nghĩa thuộc tính thẻ chứa cả định nghĩa rtexprvalue được thiết lập thành true và định nghĩa deferred-value hoặc deferred-method.

Tắt hoạt động lượng giá biểu thức

Do các mẫu xác định các biểu thức EL, ${ } và #{ }, không được giữ trong các đặc tả JSP trước JSP 2.0, nên có thể tồn tại các ứng dụng trong đó các mẫu như vậy được dự định sẽ truyền qua theo từng phần. Để ngăn không cho các mẫu được lượng giá, bạn có thể hủy bỏ lượng giá EL bằng một trong các cách sau:

  • Bỏ qua các ký tự #{ hoặc ${ trong trang.

  • Định cấu hình ứng dụng với Nhóm thuộc tính JSP.

  • Định cấu hình trang với chỉ thị của trang.

Để bỏ quá các ký tự #{ hoặc ${ trong trang, bạn sử dụng ký tự \ như sau:

some text \#{ some more\${ text
<my:tag someAttribute="sometext\#{more\${text" />

Một cách khác để huỷ kích hoạt lượng giá EL là sử dụng một nhóm thuộc tính JSP để cho phép các ký tự #{ như một literal String bằng cách sử dụng phần tử con deferred-syntax-allowed-as-literal, hoặc để điều chỉnh tất cả các biểu thức như literals bằng cách sử dụng phần tử con el-ignored:

<jsp-property-group>
    <deferred-syntax-allowed-as-literal>
        true
    </deferred-syntax-allowed-as-literal>
</jsp-property-group>

hoặc:

<jsp-property-group>
    <el-ignored>true</el-ignored>
</jsp-property-group>

Cuối cùng, bạn có thể định cấu hình trang với chỉ thị page để hoặc là chấp nhận các ký tự #{ như các ký tự String với thuộc tính deferredSyntaxAllowedAsLiteral, hoặc là bỏ qua tất cả các biểu thức EL sử dụng thuộc tính isELIgnored:

<%@page ... deferredSyntaxAllowedAsLiteral="true" %>

Hoặc:

<%@ page isELIgnored ="true" %>

Các giá trị hợp lệ của các thuộc tính này là true và false. Nếu isELIgnored là true, thì biểu thức EL sẽ bị bỏ qua khi chúng xuất hiện trong các thuộc tính của văn bản tĩnh hoặc các thuộc tính thẻ. Nếu nó là false thì các biểu thức EL được lượng giá bởi vùng chứa chỉ khi thuộc tính có rtexprvalue được đặt thành true hoặc biểu thức là biểu thức gián tiếp.

Giá trị mặc định của isELIgnored thay đổi tùy thuộc vào phiên bản của bộ mô tả triển khai ứng dụng web. Chế độ mặc định cho các trang JSP được phân phối với bộ mô tả Servlet 2.4 là để lượng giá biểu thức EL; điều này tự động cung cấp mặc định mà hầu hết các ứng dụng muốn. Chế độ mặc định cho các trang JSP được phân phối bằng mô tả từ Servlet 2.3 hoặc trước đó là bỏ qua các biểu thức EL; Điều này cung cấp khả năng tương thích ngược.

Biểu thức hằng

Biểu thức hằng dùng để lượng giá cho hằng của biểu thức, đó là kiểu String. Nó không sử dụng dấu phân cách ${} hoặc #{}.

Nếu bạn có một biểu thức hằng bao gồm cú pháp ${} hoặc #{}, bạn cần phải bỏ qua các ký tự này như sau:

  • Bằng cách tạo ra một biểu thức tổng hợp như được hiển thị ở đây:

    ${’${’}exprA}
    #{’#{’}exprB}

    Các giá trị kết quả sau đó sẽ là các chuỗi ${exprA} và #{exprB}.

  • Các ký tự thoát \ $ và \ # có thể được sử dụng để thoát khỏi những gì sẽ được coi như một biểu thức eval:

    \${exprA}
    \#{exprB}

    Các giá trị kết quả vẫn là các chuỗi ${exprA} và #{exprB}.

Khi một biểu thức hằng được lượng giá, nó có thể được chuyển đổi sang một kiểu khác. Bảng dưới đây cho ta các ví dụ về các biểu thức văn bản khác nhau và các kiểu dự kiến ​​của chúng cũng như các giá trị kết quả.

Biểu thức

Kiểu dự kiến

Kết quả

Hi

String

Hi

true

Boolean

Boolean.TRUE

42

int

42

Các biểu thức chính tả

Các biểu thức hằng có thể được lượng giá trực tiếp hoặc gián tiếp và có thể là biểu thức hoặc giá trị. Tại một điểm nào đó một biểu thức hằng được lượng giá thì phụ thuộc vào vị trí nó đang được sử dụng. Nếu thuộc tính thẻ sử dụng biểu thức văn bản được định nghĩa dưới dạng chấp nhận một biểu thức giá trị gián tiếp thì biểu thức văn bản sẽ tham chiếu một giá trị và được lượng giá tại một điểm trong chu trình sống được xác định bởi nơi biểu thức được sử dụng và tham chiếu đến.

Trong trường hợp biểu thức phương thức thì phương thức được tham chiếu sẽ được gọi và trả về hằng String đã xác định. Các thẻ CommandButton của ứng dụng Guess Number sử dụng một biểu thức phương thức hằng là một kết quả hợp lý để nói với JavaServer Faces hệ thống định vị mà trang sẽ hiển thị tiếp theo.

Thực thi biểu thức

EL hợp nhất giới thiệu một API mới, có thể áp dụng thực thi các biểu thức. Các phần chính của API này là:

  • Lớp ValueExpression dùng để định nghĩa một biểu thức giá trị

  • Lớp MethodExpression dùng để định nghĩa một biểu thức phương thức

  • Một lớp ELResolver sẽ định nghĩa một cơ chế để thực thi các biểu thức

  • Một bộ triển khai ELResolver trong đó mỗi thực thi sẽ có trách nhiệm giải quyết các biểu thức tham chiếu một kiểu đối tượng hoặc thuộc tính cụ thể

  • Một đối tượng ELContext sẽ lưu trạng thái liên quan đến độ phân giải EL, nó chứa các tham chiếu đến bộ thực thhi EL, và chứa các đối tượng ngữ cảnh (như JspContext) cần thiết bằng công nghệ cơ bản để thực hiện các biểu thức

Hầu hết các nhà phát triển ứng dụng sẽ không cần phải sử dụng các lớp này trực tiếp trừ khi họ có kế hoạch để viết các bộ thực thi EL của riêng mình. Những người viết các thành phần tùy chỉnh JavaServer Faces chắc chắn sẽ cần phải sử dụng ValueExpression và MethodExpression. Phần này sẽ trình bày chi tiết cách thức giải quyết các biểu thức vì lợi ích của các nhà phát triển này. Nó không giải thích cách để tạo ra một bộ xử lý tùy chỉnh.

Quá trình lượng giá biểu thức

Khi một biểu thức giá trị được đưa vào một trang được phân tích cú pháp trong quá trình khởi tạo yêu cầu cho trang thì một đối tượng ValueExpression được tạo ra để đại diện cho biểu thức. Sau đó, phương thức getValue của đối tượng ValueExpression sẽ được gọi ra. Phương thức này sẽ lần lượt gọi phương thức getValue của bộ giải quyết phù hợp. Một quá trình tương tự xảy ra trong quá trình postback khi setValue được gọi nếu biểu thức là một biểu thức lvalue.

Trong trường hợp là biểu thức phương thức thì một BeanELResolver được sử dụng để tìm đối tượng thực hiện phương thức được gọi hoặc truy vấn. Tương tự như quá trình đánh giá các biểu thức giá trị, khi gặp một biểu thức phương thức thì đối tượng MethodExpression sẽ được tạo ra. Sau đó, phương thức invoke hoặc getMethodInfo của đối tượng MethodExpression được gọi. Phương thức này lần lượt gọi phương thức getValue của đối tượng BeanELResolvergetMethodInfo chủ yếu được sử dụng bởi các công cụ.

Sau khi một bộ giải quyết hoàn thành độ phân giải của một biểu thức, nó sẽ đặt giá trị cờ propertyResolved của ELContext thành true để không có thêm các bộ giải quyết mẫu nào nữa.

Giải quyết EL

Ở trung tâm của máy EL là lớp ELResolver mở rộng. Một lớp mà thực hiện ELResolver sẽ định nghĩa cách để giải quyết các biểu thức đề cập đến một loại đối tượng hoặc thuộc tính đặc biệt. Trong các mục của biểu thức sau đây, một thể hiện BeanELResolver được gọi lần đầu tiên để tìm đối tượng base là employee, đó là một thành phần của JavaBeans. Khi bộ giải quyết tìm thấy đối tượng, nó được gọi lại để giải quyết property là lName của đối tượng employee.

${employee.lName}

Hệ thống EL hợp nhất bao gồm một tập các bộ triển khai bộ giải quyết tiêu chuẩn. Bảng dưới đây liệt kê những bộ giải quyết tiêu chuẩn này và bao gồm các biểu thức ví dụ mà chúng có thể giải quyết.

Resolver

Ví dụ Biểu thức

Sự miêu tả

ArrayELResolver

$ {MyArray [1]}

Trả về giá trị tại index 1 trong mảng gọi là myArray

BeanELResolver

$ {Employee.lName}

Trả về giá trị của lname tài sản của nhân viên đậu

ListELResolver

$ {MyList [5]}

Trả về giá trị tại chỉ số 5 của danh sách myList

MapELResolver

$ {MyMap.someKey}

Trả lại giá trị được lưu trữ tại khoá, someKey , trong Bản đồ , myMap

ResourceBundleELResolver

$ {MyRB.myKey}

Trả về thông báo tại myKey trong bó nguồn được gọi là myRB

Các chất giải quyết tiêu chuẩn EL

Tùy thuộc vào công nghệ sử dụng EL hợp nhất, các máy giải quyết khác có thể có sẵn. Ngoài ra, các nhà phát triển ứng dụng có thể bổ sung các triển khai của riêng mình về ELResolver để hỗ trợ giải quyết các biểu thức chưa được hỗ trợ bởi EL hợp nhất bằng cách đăng ký chúng với một ứng dụng.

Tất cả các máy xử lý tiêu chuẩn và tùy chỉnh có sẵn cho một ứng dụng cụ thể được thu thập trong một chuỗi theo một thứ tự cụ thể. Chuỗi giải quyết này được biểu diễn bằng một ví dụ có tên CompositeELResolver. Khi gặp phải một biểu thức thì thể hiện CompositeELResolver sẽ lặp qua danh sách các giải quyết và tư vấn cho mỗi bộ giải quyết cho đến khi nó tìm thấy một trong đó có thể xử lý các biểu thức.

Nếu một ứng dụng được sử dụng công nghệ JSP thì chuỗi phân giải sẽ bao gồm ImplicitObjectELResolver và ScopedAttributeELResolver.

Đối tượng ẩn

Ngôn ngữ biểu thức JSP định nghĩa một tập hợp các đối tượng ngầm định:

  • PageContext: Ngữ cảnh cho trang JSP. Nó cung cấp việc truy cập vào các đối tượng khác nhau bao gồm:

    • servletContext: Khung cảnh của servlet của trang JSP và bất kỳ thành phần web nào chứa trong cùng một ứng dụng. Xem Truy cập Bối cảnh Web .

    • session: Đối tượng session đối với client.

    • request: Yêu cầu kích hoạt việc thực hiện trang JSP.

    • response: Phản hồi trả về bởi trang JSP.

  • Ngoài ra, một số đối tượng tiềm ẩn có sẵn cho phép dễ dàng truy cập vào các đối tượng sau:

    • param : Lập chỉ mục tên thông số yêu cầu cho một giá trị duy nhất

    • paramValues : Lập bản đồ tên tham số yêu cầu cho một mảng các giá trị

    • header: ánh xạ tên tiêu đề yêu cầu đến một giá trị duy nhất

    • headerValues : Lập một tên tiêu đề yêu cầu cho một mảng các giá trị

    • cookie : ánh xạ tên cookie với một cookie duy nhất

    • initParam : Lập chỉ mục tên tham số khởi tạo cho một giá trị

  • Cuối cùng, có các đối tượng cho phép truy cập vào các biến phạm vi khác nhau được mô tả như sau:

    • pageScope : Các ánh xạ tên biến được định nghĩa bởi trang với giá trị của chúng

    • requestScope : Các ánh xạ tên biến yêu cầu với các giá trị của chúng

    • sessionScope : Các ánh xạ tên biến được yêu cầu với các giá trị của chúng

    • applicationScope : Các ánh xạ tên biến ứng dụng với các giá trị của chúng

JSP 2.1 cung cấp hai bộ giải quyết EL để xử lý các biểu thức tham chiếu đến các đối tượng này là ImplicitObjectELResolver và ScopedAttributeELResolver.

Một biến phù hợp với một trong những đối tượng ngầm định được đánh giá bởi ImplicitObjectResolver, nó trả về đối tượng ngầm định. Trình giải quyết này chỉ xử lý các biểu thức với một giá trị null. Điều gì sẽ xảy ra đối với biểu thức sau đây khi mà ImplicitObjectResolver chỉ giải quyết đối tượng ngầm định là sessionScope. Một khi đối tượng ngầm định được tìm thấy thì thuộc tính MapELResolver sẽ giải quyết thuộc tính profile vì đối tượng profile đại diện cho một ánh xạ.

${sessionScope.profile}

ScopedAttributeELResolver sẽ lượng giá một đối tượng duy nhất được lưu trữ trong phạm vi. Giống như ImplicitObjectELResolver, nó cũng chỉ lượng giá các biểu thức dựa trên null. Trình giải quyết vấn đề này sẽ tìm kiếm một đối tượng trong tất cả các phạm vi cho đến khi nó tìm thấy, theo hành vi của PageContext.findAttribute(String). Ví dụ: khi lượng giá biểu thức ${product} thì bộ giải quyết sẽ tìm kiếm product trong trang, yêu cầu, phiên và các phạm vi ứng dụng và sẽ trả lại giá trị của nó. Nếu product không được tìm thấy thì sẽ trả về null.

Khi một biểu thức tham chiếu một trong những đối tượng ngầm định theo tên thì đối tượng thích hợp sẽ được trả về thay vì thuộc tính tương ứng. Ví dụ: ${pageContext} trả về đối tượng PageContext ngày cả nếu có một thuộc tính pageContext có chứa một số giá trị khác.

Các toán tử

Ngoài các toán tử và [] thì ngôn ngữ biểu thức JSP cung cấp cho các toán tử sau, có thể chỉ được sử dụng trong các biểu thức rvalue:

  • Số học+ , - (nhị phân), * , / và div , % và mod , - (unary)

  • Logic: and, && , or , || not , !

  • Relational== , eq , != , ne , < , lt , > , gt , <= , ge , > = , le. Các phép toán so sánh có thể được thực hiện dựa trên các giá trị khác, hoặc dựa trên các hằng boolean, string, integer hoặc floating point.

  • Empty: Toán tử empty là một hoạt động tiền tố có thể được sử dụng để xác định một giá trị là null hoặc rỗng.

  • Điều kiệnA ? B: C. Trả về B hoặc C , tùy thuộc vào kết quả của A.

Mức độ ưu tiên của các toán tử từ cao nhất đến thấp nhất, từ trái sang phải như sau:

  • [] .

  • () (Được sử dụng để thay đổi sự ưu tiên của các toán tử)

  • - (một ngôi) not ! empty

  • * / div % mod

  • + - (2 ngôi)

  • <> <=> = lt gt le ge

  • ==! = eq ne

  • && and

  • || or

  • ? :

Từ riêng

Các từ sau được dành riêng cho ngôn ngữ biểu thức JSP và không được sử dụng làm định danh.

and

or

not

eq

ne

lt

gt

le

ge

true

false

null

instanceof

empty

div

mod

Lưu ý rằng đa số những từ này không có trong ngôn ngữ bây giờ, nhưng chúng có thể trong tương lai, vì vậy bạn nên tránh sử dụng chúng.

Ví dụ về biểu thức EL

Bảng sau đây chứa các biểu thức EL ví dụ và kết quả lượng giá chúng.

Biểu thức EL

Kết quả

${1 > (4/2)}

false

${4.0 >= 3}

true

${100.0 == 100}

true

${(10*10) ne 100}

false

${'a' < 'b'}

true

${'hip' gt 'hit'}

false

${4 > 3}

true

${1.2E4 + 1.4}

12001.4

${3 div 4}

0.75

${10 mod 4}

2

${!empty param.Add}

False nếu tham số yêu cầu có tên Add là null hoặc một chuỗi rỗng.

${pageContext.request.contextPath}

Đường dẫn ngữ cảnh.

${sessionScope.cart.numberOfItems}

Giá trị của thuộc tính numberOfItems của thuộc tính phạm vi phiên có tên cart.

${param['mycom.productId']}

Giá trị của tham số yêu cầu có tên mycom.productId.

${header["host"]}

host.

${departments[deptName]}

Giá trị của đầu vào có tên deptName trong ánh xạ departments.

${requestScope[’javax.servlet.forward.servlet_path’]}

Giá trị của thuộc tính phạm vi yêu cầu có tên javax.servlet.forward.servlet_path.

#{customer.lName}

Lấy giá trị của thuộc tính lName từ bean customer trong quá trình khởi tạo một yêu cầu. Thiết lập giá trị của lName trong một postback.

#{customer.calcTotal}

Trả về giá trị của phương thức calcTotal của bean customer.

Các biểu thức ví dụ

Hàm

Ngôn ngữ biểu thức JSP cho phép bạn tạo hàm và có thể được gọi trong một biểu thức. Hàm được định nghĩa bằng cách sử dụng cùng các cơ chế như các thẻ tùy chỉnh.

Thoạt nhìn thì các hàm có vẻ tương tự như các biểu thức của phương thức, nhưng chúng khác vì những điểm sau:

  • Các hàm tham chiếu đến các phương thức tĩnh để trả về một giá trị. Biểu thức phương thức thì tham chiếu đến các phương thức public không tĩnh, tùy ý đối với các đối tượng.

  • Hàm được nhận diện tĩnh tại thời gian dịch, trong khi phương thức được nhận diện là động khi chạy.

  • Here>>>>>Các tham số hàm và các lời gọi được xác định như một phần của biểu thức EL. Một biểu thức phương thức chỉ xác định một phương thức cụ thể. Việc gọi phương thức đó không được xác định bởi biểu thức EL; Thay vào đó, nó được xác định trong định nghĩa thuộc tính thẻ của thuộc tính bằng cách sử dụng biểu thức phương thức, như mô tả trong Định nghĩa một Loại Thuộc tính Thẻ .

Sử dụng hàm

Các hàm có thể xuất hiện trong các giá trị thuộc tính tĩnh và giá trị thuộc tính thẻ.

Để sử dụng một hàm trong trong một trang JSP, bạn sử dụng một chỉ thị taglib để nhập thư viện thẻ chứa hàm. Sau đó bạn khai báo hàm gọi với tiền tố được khai báo trong chỉ thị.

Ví dụ: ở ví dụ date thì trang index.jsp sẽ nhập thư viện /functions và gọi hàm equal với một biểu thức:

<%@ taglib prefix="f" uri="/functions"%>
...
        <c:when
            test="${f:equals(selectedLocaleString,
                localeString)}" >

Trong ví dụ này, biểu thức tham chiếu hàm được sử dụng cú pháp lượng giá trực tiếp. Một tác giả trang cũng có thể sử dụng cú pháp lượng giá gián tiếp để tham chiếu một hàm trong một biểu thức, giả sử rằng thuộc tính tham chiếu đến hàm có thể chấp nhận các biểu thức gián tiếp.

Nếu một thuộc tính tham chiếu một hàm với biểu thức gián tiếp thì hàm đó không được gọi trực tiếp; thay vào đó, nó được gọi ra bất cứ khi nào công nghệ nền sử dụng hàm xác định nó cần được gọi.

Định nghĩa hàm

Để định nghĩa một hàm, hãy lập trình nó như một phương thức public static trong một lớp public. Lớp mypkg.MyLocales trong ví dụ date định nghĩa một hàm kiểm tra sự giống nhau của hai chuỗi St như sau:

package mypkg;
public class MyLocales {

    ...
    public static boolean equals( String l1, String l2 ) {
        return l1.equals(l2);
    }
}

Sau đó ánh xạ tên chức năng như sử dụng trong biểu thức EL để xác định lớp và signature của hàm trong một TLD. Tệp functions.tld sau đây trong ví dụ date sẽ ánh xạ hàm equals tới lớp có chứa thực thi của hàm equals và signature của hàm:

<function>
    <name>equals</name>
    <function-class>mypkg.MyLocales</function-class>
    <function-signature>boolean equals( java.lang.String,
        java.lang.String )</function-signature>
</function>

Lưu ý rằng không được phép có 2 hàm cùng tên trong thư viện thẻ.

» Tiếp: Các thành phần JavaBeans
« Trước: Tạo nội dung tĩnh và động
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!