Các câu hỏi phỏng vấn JSP rất quan trọng nếu bạn đang tham gia một cuộc phỏng vấn về Java. JSP là một phần không thể thiếu của bất kỳ ứng dụng web Java EE nào và gần đây tôi đã viết rất nhiều về các tính năng khác nhau trong JSP.

Chúng ta sẽ bắt đầu từ những điều cơ bản của JSP, JSP scripting (kịch bản JSP) và kết thúc với JSP custom tags (thẻ tùy chỉnh JSP) để tránh mã Java trong các trang JSP.
Các câu hỏi phỏng vấn JSP phổ biến
Tôi có một số câu hỏi và câu trả lời phỏng vấn JSP quan trọng để giúp bạn trong các cuộc phỏng vấn đây. Đây là những câu hỏi và câu trả lời phỏng vấn JSP hay dành cho cả lập trình viên có kinh nghiệm và người mới bắt đầu.
1. JSP là gì và tại sao chúng ta cần nó?
JSP là viết tắt của JavaServer Pages, là công nghệ phía máy chủ Java để tạo các trang web động. JSP là phần mở rộng của công nghệ Servlet để giúp các nhà phát triển tạo các trang động với cú pháp giống HTML.
Chúng ta cũng có thể tạo các khung nhìn người dùng trong Servlet nhưng mã sẽ trở nên rất khó coi và dễ gây lỗi. Ngoài ra, hầu hết các phần tử trên một trang web là tĩnh, vì vậy trang JSP phù hợp hơn cho các trang web.
Chúng ta nên tránh logic nghiệp vụ trong các trang JSP và cố gắng chỉ sử dụng nó cho mục đích hiển thị. Các phần tử scripting JSP có thể được sử dụng để viết mã Java trong các trang JSP nhưng tốt nhất nên tránh chúng và sử dụng các phần tử hành động JSP, thẻ JSTL hoặc thẻ tùy chỉnh để đạt được các chức năng tương tự.
Một lợi ích nữa của JSP là hầu hết các container hỗ trợ triển khai nóng (hot deployment) các trang JSP. Chỉ cần thực hiện các thay đổi cần thiết trong trang JSP và thay thế trang cũ bằng trang JSP đã cập nhật trong thư mục triển khai và container sẽ tải trang JSP mới.
Chúng ta không cần biên dịch mã dự án hoặc khởi động lại máy chủ, trong khi nếu chúng ta thay đổi mã Servlet, chúng ta cần xây dựng lại toàn bộ dự án và triển khai nó. Mặc dù hầu hết các container hiện nay đều hỗ trợ triển khai nóng cho các ứng dụng, nhưng vẫn phức tạp hơn so với các trang JSP.
2. Các giai đoạn trong vòng đời JSP là gì?
Nếu bạn xem mã trang JSP, nó trông giống HTML và không giống bất kỳ lớp Java nào. Trên thực tế, container JSP chịu trách nhiệm dịch các trang JSP và tạo lớp Servlet được sử dụng trong ứng dụng web. Các giai đoạn vòng đời JSP là:
- Dịch (Translation) – Container JSP kiểm tra mã trang JSP và phân tích cú pháp để tạo mã nguồn Servlet. Ví dụ, trong Tomcat, bạn sẽ tìm thấy các tệp lớp Servlet được tạo tại thư mục
TOMCAT/work/Catalina/localhost/WEBAPP/org/apache/jsp. Nếu tên trang JSP làhome.jsp, thông thường tên lớp Servlet được tạo làhome_jspvà tên tệp làhome_jsp.java. - Biên dịch (Compilation) – Container JSP biên dịch mã nguồn lớp JSP và tạo tệp
.classtrong giai đoạn này. - Tải lớp (Class Loading) – Container tải lớp vào bộ nhớ trong giai đoạn này.
- Khởi tạo đối tượng (Instantiation) – Container gọi hàm tạo không đối số của lớp được tạo để tải nó vào bộ nhớ và khởi tạo đối tượng.
- Khởi tạo (Initialization) – Container gọi phương thức
initcủa đối tượng lớp JSP và khởi tạo cấu hình Servlet với các tham số khởi tạo được cấu hình trong deployment descriptor (tệp mô tả triển khai). Sau giai đoạn này, JSP sẵn sàng xử lý các yêu cầu của khách hàng. Thông thường, quá trình từ dịch đến khởi tạo JSP xảy ra khi yêu cầu đầu tiên đến JSP, nhưng chúng ta có thể cấu hình nó để được tải và khởi tạo tại thời điểm triển khai giống như Servlet sử dụng phần tửload-on-startup. - Xử lý yêu cầu (Request Processing) – Đây là vòng đời dài nhất của trang JSP và trang JSP xử lý các yêu cầu của khách hàng. Quá trình xử lý đa luồng và tương tự như Servlet, và đối với mỗi yêu cầu, một luồng mới được tạo và đối tượng
ServletRequestvàServletResponseđược tạo, đồng thời phương thức dịch vụ JSP được gọi. - Hủy (Destroy) – Đây là giai đoạn cuối cùng của vòng đời JSP, nơi lớp JSP được dỡ khỏi bộ nhớ. Thông thường nó xảy ra khi ứng dụng bị gỡ triển khai hoặc máy chủ bị tắt.
3. Các phương thức vòng đời JSP là gì?
Các phương thức vòng đời JSP là:
jspInit(): Phương thức này được khai báo trongJspPagevà nó được triển khai bởi các cài đặt của container JSP. Phương thức này được gọi một lần trong vòng đời JSP để khởi tạo nó với các tham số cấu hình được cấu hình trong deployment descriptor. Chúng ta có thể ghi đè phương thức này bằng cách sử dụng phần tử scripting khai báo JSP để khởi tạo bất kỳ tài nguyên nào mà chúng ta muốn sử dụng trong trang JSP._jspService(): Đây là phương thức JSP được container JSP gọi cho mỗi yêu cầu của khách hàng bằng cách truyền đối tượng request và response. Lưu ý rằng tên phương thức bắt đầu bằng dấu gạch dưới để phân biệt nó với các phương thức vòng đời khác vì chúng ta không thể ghi đè phương thức này. Tất cả mã JSP nằm bên trong phương thức này và nó được ghi đè theo mặc định. Chúng ta không nên cố gắng ghi đè nó bằng cách sử dụng phần tử scripting khai báo JSP. Phương thức này được định nghĩa trong giao diệnHttpJspPage.jspDestroy(): Phương thức này được container gọi khi JSP được dỡ khỏi bộ nhớ, chẳng hạn như tắt ứng dụng hoặc container. Phương thức này chỉ được gọi một lần trong vòng đời JSP và chúng ta nên ghi đè phương thức này để giải phóng bất kỳ tài nguyên nào được tạo trong phương thứcjspInit().
4. Các phương thức vòng đời JSP nào có thể bị ghi đè?
Chúng ta có thể ghi đè các phương thức jspInit() và jspDestroy() bằng cách sử dụng phần tử scripting khai báo JSP. Chúng ta nên ghi đè các phương thức jspInit() để tạo các tài nguyên chung mà chúng ta muốn sử dụng trong phương thức dịch vụ JSP và ghi đè phương thức jspDestroy() để giải phóng các tài nguyên chung.
5. Làm thế nào chúng ta có thể tránh truy cập trực tiếp các trang JSP từ trình duyệt của khách hàng?
Chúng ta biết rằng bất cứ thứ gì bên trong thư mục WEB-INF đều không thể truy cập trực tiếp trong một ứng dụng web, vì vậy chúng ta có thể đặt các trang JSP của mình vào thư mục WEB-INF để tránh truy cập trực tiếp trang JSP từ trình duyệt của client. Nhưng trong trường hợp này, chúng ta sẽ phải cấu hình nó trong deployment descriptor (bộ mô tả triển khai) giống như Servlets. Cấu hình mẫu được cung cấp trong đoạn mã web.xml dưới đây
<servlet> <servlet-name>Test</servlet-name> <jsp-file>/WEB-INF/test.jsp</jsp-file> <init-param> <param-name>test</param-name> <param-value>Test Value</param-value> </init-param> </servlet>
<servlet-mapping> <servlet-name>Test</servlet-name> <url-pattern>/Test.do</url-pattern> </servlet-mapping>
6. Các loại chú thích khác nhau trong JSP là gì?
Có hai loại chú thích mà chúng ta có thể sử dụng trong các trang JSP:
- HTML Comments (Chú thích HTML): Vì các trang JSP giống như HTML, chúng ta có thể sử dụng chú thích HTML như “. Những chú thích này cũng được gửi đến client và chúng ta có thể thấy chúng trong mã nguồn HTML. Vì vậy, chúng ta nên tránh sử dụng chú thích HTML cho các bình luận cấp độ mã hoặc gỡ lỗi.
- JSP Comments (Chú thích JSP): Chú thích JSP được viết bằng các scriptlet như
<%-- JSP Comment --%>. Những chú thích này có trong mã nguồn servlet được tạo ra và không được gửi đến client. Đối với bất kỳ thông tin chú thích nào liên quan đến mã hoặc gỡ lỗi, chúng ta nên sử dụng chú thích JSP.
7. Scriptlet, Expression và Declaration trong JSP là gì?
Scriptlet, Expression và Declaration là các phần tử scripting trong trang JSP, thông qua đó chúng ta có thể thêm mã Java vào các trang JSP. Một thẻ scriptlet bắt đầu bằng <% và kết thúc bằng %>. Bất kỳ mã nào được viết bên trong các thẻ scriptlet đều sẽ được đưa vào phương thức _jspService(). Ví dụ:
<% Date d = new Date(); System.out.println(“Current Date=”+d); %>
Since most of the times we print dynamic data in JSP page using _out.print()_ method, there is a shortcut to do this through JSP Expressions. JSP Expression starts with `<%=` and ends with `%>`. `<% out.print("Pankaj"); %>` can be written using JSP Expression as `<%= "Pankaj" %>` Notice that anything between `<%= %>` is sent as parameter to `out.print()` method. Also notice that scriptlets can contain multiple java statements and always ends with semicolon (;) but expression doesn't end with semicolon. JSP Declarations are used to declare member methods and variables of servlet class. JSP Declarations starts with `<%!` and ends with `%>`. For example we can create an int variable in JSP at class level as `<%! public static int count=0; %>`.
8. Các đối tượng ngầm định trong JSP là gì?
Các đối tượng ngầm định (implicit objects) trong JSP được container tạo ra trong quá trình dịch trang JSP sang mã nguồn Servlet để hỗ trợ các nhà phát triển. Chúng ta có thể sử dụng trực tiếp các đối tượng này trong các scriptlet (phần tử kịch bản) vốn được đưa vào phương thức _jspService(). Tuy nhiên, chúng ta không thể sử dụng chúng trong JSP Declaration (khai báo JSP) vì mã đó sẽ nằm ở cấp độ lớp.
Chúng ta có 9 đối tượng ngầm định có thể sử dụng trực tiếp trong trang JSP. Bảy trong số đó được khai báo là biến cục bộ ngay từ đầu phương thức _jspService(), trong khi hai đối tượng còn lại là một phần của đối số phương thức _jspService() mà chúng ta có thể sử dụng.
- Đối tượng
out - Đối tượng
request - Đối tượng
response - Đối tượng
config - Đối tượng
application - Đối tượng
session - Đối tượng
pageContext - Đối tượng
page - Đối tượng
exception - Ví dụ về các đối tượng ngầm định trong JSP
9. Chúng ta có thể sử dụng các đối tượng ngầm định JSP trong một phương thức được định nghĩa trong Khai báo JSP không?
Không, chúng ta không thể sử dụng các đối tượng ngầm định JSP trong một phương thức được định nghĩa trong khai báo JSP. Lý do là các đối tượng ngầm định JSP mang tính cục bộ đối với phương thức _jspService() và được JSP Container thêm vào khi dịch trang JSP sang mã nguồn servlet. Trong khi đó, mã trong các khai báo JSP lại nằm bên ngoài phương thức _jspService() và được dùng để tạo các biến và phương thức ở cấp độ lớp, do đó không thể sử dụng các đối tượng ngầm định JSP.
10. Đối tượng ngầm định nào không có sẵn trong các trang JSP thông thường?
Đối tượng ngầm định exception trong JSP không có sẵn trong các trang JSP thông thường. Nó chỉ được sử dụng trong các trang lỗi JSP để bắt các ngoại lệ được ném ra từ các trang JSP và cung cấp thông báo hữu ích cho client.
11. Đối tượng ngầm định PageContext mang lại những lợi ích gì?
Đối tượng ngầm định pageContext trong JSP là một thể hiện (instance) của việc triển khai lớp trừu tượng javax.servlet.jsp.PageContext. Chúng ta có thể sử dụng pageContext để lấy và thiết lập các thuộc tính với các phạm vi khác nhau, và để chuyển tiếp yêu cầu đến các tài nguyên khác. Đối tượng pageContext cũng chứa tham chiếu đến các đối tượng ngầm định khác. Đây là đối tượng duy nhất phổ biến trong cả các đối tượng ngầm định JSP và các đối tượng ngầm định JSP EL (Expression Language).
12. Làm thế nào để chúng ta cấu hình các tham số khởi tạo (init params) cho JSP?
Chúng ta có thể cấu hình tham số khởi tạo (init params) cho JSP tương tự như Servlet trong tệp web.xml. Chúng ta cần cấu hình các tham số khởi tạo JSP bằng các phần tử servlet và servlet-mapping. Điểm khác biệt duy nhất so với Servlet là phần tử jsp-file, nơi chúng ta cần cung cấp vị trí của trang JSP.
13. Tại sao việc sử dụng các phần tử scripting trong JSP lại không được khuyến khích?
Các trang JSP chủ yếu được sử dụng cho mục đích hiển thị (view), và tất cả logic nghiệp vụ nên nằm trong các lớp Servlet hoặc model. Chúng ta nên truyền các tham số đến trang JSP thông qua các thuộc tính (attributes) và sau đó sử dụng chúng để tạo phản hồi HTML trong trang JSP. Hầu hết các trang JSP chứa mã HTML và để giúp các nhà thiết kế web dễ dàng hiểu và phát triển trang JSP, công nghệ JSP cung cấp các phần tử hành động (action elements), JSP EL (Expression Language), JSTL (JSP Standard Tag Library) và thẻ tùy chỉnh (custom tags) mà chúng ta nên sử dụng thay vì các phần tử scripting để bắc cầu giữa phần HTML và phần Java của JSP.
14. Chúng ta có thể định nghĩa một lớp trong một trang JSP không?
Mặc dù đây không phải là một thực hành tốt, nhưng chúng ta có thể định nghĩa một lớp bên trong một trang JSP. Dưới đây là mã mẫu cho điều này:
<%! private static class NestedClass { //static is better because Servlet is multi-threaded private final int num = 0; public int getNum() { return num; } } %>
Or
<% class Person { //this will go inside method body, so can’t be public } %>
15. Làm thế nào chúng ta có thể vô hiệu hóa mã Java hoặc scripting trong trang JSP?
Chúng ta có thể vô hiệu hóa các phần tử scripting trong các trang JSP thông qua cấu hình deployment descriptor như sau:
<jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <scripting-invalid>true</scripting-invalid> </jsp-property-group> </jsp-config>
url-pattern ở trên sẽ vô hiệu hóa scripting cho tất cả các trang JSP, nhưng nếu bạn muốn vô hiệu hóa nó chỉ cho một trang cụ thể, bạn có thể chỉ định tên tệp JSP đó.
16. Giải thích các phần tử hành động JSP hoặc thẻ hành động (Action Tags)?
Các phần tử hành động JSP hoặc thẻ hành động là các thẻ giống HTML cung cấp các chức năng hữu ích như làm việc với Java Bean, bao gồm một tài nguyên (resource), chuyển tiếp yêu cầu và tạo các phần tử XML động. Các phần tử hành động JSP luôn bắt đầu bằng tiền tố jsp: và chúng ta có thể sử dụng chúng trực tiếp trong trang JSP mà không cần phải import bất kỳ thư viện thẻ nào hoặc thay đổi cấu hình khác. Một số phần tử hành động quan trọng là jsp:useBean, jsp:getProperty, jsp:setProperty, jsp:include và jsp:forward.
17. Sự khác biệt giữa include directive và jsp:include action là gì?
Sự khác biệt giữa include directive và include action trong JSP là:
- Trong include directive, nội dung từ tài nguyên khác được thêm vào mã servlet được tạo ra tại thời điểm dịch (translation).
- Trong khi đó, với include action, việc này xảy ra tại thời điểm chạy (runtime).
Một khác biệt nữa là trong JSP include action, chúng ta có thể truyền các tham số để sử dụng trong tài nguyên được bao gồm bằng cách sử dụng phần tử hành động jsp:param, nhưng trong JSP include directive, chúng ta không thể truyền bất kỳ tham số nào.
Khi tài nguyên được bao gồm là tĩnh (chẳng hạn như header, footer, tệp hình ảnh), chúng ta nên sử dụng include directive để có hiệu suất nhanh hơn. Tuy nhiên, nếu tài nguyên được bao gồm là động và yêu cầu một số tham số để xử lý, thì chúng ta nên sử dụng include action tag.
18. JSP Expression Language là gì và lợi ích của nó là gì?
Hầu hết thời gian chúng ta sử dụng JSP cho mục đích hiển thị (view) và tất cả logic nghiệp vụ đều nằm trong mã servlet hoặc các lớp model. Khi chúng ta nhận yêu cầu từ client trong servlet, chúng ta xử lý nó và sau đó thêm các thuộc tính vào phạm vi request/session/context để được truy xuất trong mã JSP. Chúng ta cũng sử dụng các tham số yêu cầu (request params), headers, cookies và init params trong JSP để tạo các khung nhìn phản hồi.
Chúng ta có thể sử dụng các scriptlet và JSP expressions để truy xuất các thuộc tính và tham số trong JSP bằng mã Java và sử dụng nó cho mục đích hiển thị. Nhưng đối với các nhà thiết kế web, mã Java rất khó hiểu, và đó là lý do tại sao JSP Specs 2.0 đã giới thiệu Expression Language (EL). Thông qua EL, chúng ta có thể dễ dàng lấy các thuộc tính và tham số bằng cách sử dụng các thẻ giống HTML. Cú pháp của Expression Language là ${name} và chúng ta có thể sử dụng các đối tượng ngầm định EL và toán tử EL để truy xuất các thuộc tính từ các phạm vi khác nhau và sử dụng chúng trong trang JSP.
19. Các đối tượng ngầm định của JSP EL là gì và chúng khác gì so với các đối tượng ngầm định JSP?
JSP Expression Language cung cấp nhiều đối tượng ngầm định mà chúng ta có thể sử dụng để lấy các thuộc tính từ các phạm vi khác nhau và các giá trị tham số. Lưu ý rằng những đối tượng này khác với các đối tượng ngầm định JSP và chỉ chứa các thuộc tính trong phạm vi đã cho. Đối tượng ngầm định duy nhất phổ biến trong cả JSP EL và trang JSP là đối tượng pageContext. Bảng dưới đây cung cấp danh sách các đối tượng ngầm định trong JSP EL.
| JSP EL Implicit Objects | Type | Description |
|---|---|---|
| pageScope | Map | Một Map chứa các thuộc tính được thiết lập với phạm vi trang (page scope). |
| requestScope | Map | Dùng để lấy giá trị thuộc tính với phạm vi yêu cầu (request scope). |
| sessionScope | Map | Dùng để lấy giá trị thuộc tính với phạm vi phiên (session scope). |
| applicationScope | Map | Dùng để lấy giá trị thuộc tính từ phạm vi ứng dụng (application scope). |
| param | Map | Dùng để lấy giá trị tham số yêu cầu (request parameter), trả về một giá trị duy nhất. |
| paramValues | Map | Dùng để lấy các giá trị tham số yêu cầu trong một mảng, hữu ích khi tham số yêu cầu chứa nhiều giá trị. |
| header | Map | Dùng để lấy thông tin header của yêu cầu. |
| headerValues | Map | Dùng để lấy các giá trị header trong một mảng. |
| cookie | Map | Dùng để lấy giá trị cookie trong JSP. |
| initParam | Map | Dùng để lấy các tham số khởi tạo ngữ cảnh (context init params), chúng ta không thể sử dụng nó cho các tham số khởi tạo servlet (servlet init params). |
| pageContext | pageContext | Giống như đối tượng pageContext ngầm định của JSP, dùng để lấy các tham chiếu request, session, v.v. Ví dụ sử dụng là lấy tên phương thức HTTP của yêu cầu. |
20. Làm thế nào để sử dụng JSP EL để lấy tên phương thức HTTP?
Chúng ta có thể sử dụng đối tượng ngầm định JSP EL pageContext để lấy tham chiếu đối tượng request và sử dụng toán tử dấu chấm (.) để lấy tên phương thức HTTP trong trang JSP. Mã JSP EL cho điều này sẽ là ${pageContext.request.method}.
21. JSP Standard Tag Library là gì, hãy cung cấp một vài ví dụ sử dụng?
JSP Standard Tag Library (JSTL) linh hoạt hơn JSP EL hay các phần tử Action vì chúng ta có thể lặp qua một collection hoặc thoát các thẻ HTML để hiển thị chúng như văn bản trong phản hồi. JSTL là một phần của Java EE API và được bao gồm trong hầu hết các servlet container.
Tuy nhiên, để sử dụng JSTL trong các trang JSP của mình, chúng ta cần tải xuống các tệp .jar của JSTL cho servlet container của bạn. Thông thường, bạn có thể tìm thấy chúng trong các dự án ví dụ và sử dụng chúng. Bạn cần đưa các thư viện này vào thư mục WEB-INF/lib của dự án. Các tệp .jar này là dành riêng cho từng container, ví dụ, trong Tomcat, chúng ta cần đưa các tệp jstl.jar và standard.jar vào đường dẫn xây dựng của dự án.
22. Các loại thẻ (tag) JSTL là gì?
Dựa trên các chức năng của JSTL, chúng được phân loại thành năm loại:
- Core Tags: Các thẻ này hỗ trợ lặp (iteration), logic điều kiện (conditional logic), bắt ngoại lệ (catch exception), URL, chuyển tiếp (forward) hoặc chuyển hướng (redirect) phản hồi, v.v.
- Formatting and Localization Tags: Các thẻ này được cung cấp để định dạng số (Numbers), ngày tháng (Dates) và hỗ trợ quốc tế hóa (i18n) thông qua các locale và resource bundle.
- SQL Tags: JSTL SQL Tags hỗ trợ tương tác với các cơ sở dữ liệu quan hệ như Oracle, MySQL, v.v.
- XML Tags: Các thẻ XML được sử dụng để làm việc với các tài liệu XML như phân tích XML (parsing XML), chuyển đổi dữ liệu XML (transforming XML data) và đánh giá biểu thức XPath (XPath expressions evaluation).
- JSTL Functions Tags: Các thẻ JSTL cung cấp một số hàm mà chúng ta có thể sử dụng để thực hiện các thao tác phổ biến, hầu hết chúng là để thao tác chuỗi (String manipulation) như nối chuỗi (String Concatenation), tách chuỗi (Split String), v.v.
23. JSP Custom Tag là gì và các thành phần của nó là gì?
Đôi khi JSP EL, Action Tags và JSTL tags không đủ và chúng ta có thể bị cám dỗ viết mã Java để thực hiện một số thao tác trong trang JSP. May mắn thay, JSP có thể mở rộng và chúng ta có thể tạo các thẻ tùy chỉnh của riêng mình để thực hiện các thao tác nhất định.
Chúng ta có thể tạo các JSP Custom Tags với các thành phần sau:
- JSP Custom Tag Handler: Trình xử lý thẻ tùy chỉnh JSP
- Creating Tag Library Descriptor (TLD) File: Tạo tệp mô tả thư viện thẻ (TLD)
- Deployment Descriptor Configuration for TLD: Cấu hình bộ mô tả triển khai cho TLD
Chúng ta có thể thêm thư viện thẻ tùy chỉnh vào trang JSP bằng cách sử dụng taglib directive và sau đó sử dụng nó.
24. Đưa ra một ví dụ nơi bạn cần JSP Custom Tag?
Giả sử chúng ta muốn hiển thị một số với định dạng dấu phẩy và dấu cách. Điều này có thể rất hữu ích cho người dùng khi số đó rất dài. Vì vậy, chúng ta muốn một số thẻ tùy chỉnh như sau:
<mytags:formatNumber number="123456.789" format="#,###.00"/>
Dựa trên số và định dạng được truyền, nó sẽ ghi số đã định dạng vào trang JSP, ví dụ trên nó sẽ in ra 123,456.79. Chúng ta biết rằng JSTL không cung cấp bất kỳ thẻ tích hợp nào để đạt được điều này, vì vậy chúng ta sẽ tạo một triển khai thẻ tùy chỉnh của riêng mình và sử dụng nó trong trang JSP.
25. Tại sao chúng ta không cần cấu hình các thẻ chuẩn JSP trong web.xml?
Chúng ta không cần cấu hình các thẻ chuẩn JSP trong web.xml vì các tệp TLD (Tag Library Descriptor) nằm bên trong thư mục META-INF của các tệp .jar của JSTL. Khi container tải ứng dụng web và tìm thấy các tệp TLD bên trong thư mục META-INF của tệp JAR, nó sẽ tự động cấu hình chúng để có thể sử dụng trực tiếp trong các trang JSP của ứng dụng. Tất cả những gì chúng ta cần làm là đưa nó vào trang JSP bằng cách sử dụng taglib directive.
26. Chúng ta có thể xử lý các ngoại lệ được ném ra bởi phương thức dịch vụ JSP như thế nào?
Để xử lý các ngoại lệ được ném ra bởi trang JSP, tất cả những gì chúng ta cần là một trang lỗi và định nghĩa trang lỗi đó trong JSP bằng cách sử dụng page directive. Để tạo một trang lỗi JSP, chúng ta cần đặt thuộc tính isErrorPage của page directive thành true. Sau đó, chúng ta có thể truy cập đối tượng ngầm định exception trong JSP và sử dụng nó để gửi một thông báo lỗi tùy chỉnh đến client. Chúng ta cần định nghĩa các trang JSP xử lý ngoại lệ và lỗi trong deployment descriptor như sau:
<error-page> <error-code>404</error-code> <location>/error.jsp</location> </error-page>
<error-page> <exception-type>java.lang.Throwable</exception-type> <location>/error.jsp</location> </error-page>
27. Chúng ta bắt ngoại lệ và xử lý nó bằng JSTL như thế nào?
Chúng ta có thể sử dụng các thẻ JSTL Core c:catch và c:if để bắt ngoại lệ bên trong phương thức dịch vụ JSP và xử lý nó. Thẻ c:catch sẽ bắt ngoại lệ và gói gọn nó vào biến exception, và chúng ta có thể sử dụng thẻ điều kiện c:if để xử lý nó. Đoạn mã dưới đây cung cấp ví dụ sử dụng:
<c:catch var =”exception”> <% int x = 5/0;%> </c:catch>
<c:if test = “${exception ne null}”> <p>Exception is : ${exception} <br /> Exception Message: ${exception.message}</p> </c:if>
Lưu ý việc sử dụng JSP EL trong điều kiện c:if.
28. Làm thế nào để in “<br> creates a new line in HTML” trong JSP?
Chúng ta có thể sử dụng thuộc tính escapeXml của thẻ c:out để thoát các phần tử HTML, để chúng được hiển thị dưới dạng văn bản trong trình duyệt. Đối với trường hợp này, chúng ta sẽ viết mã như sau:
<c:out value="<br> creates a new line in HTML" escapeXml="true"></c:out>
29. jsp-config trong deployment descriptor là gì?
Phần tử jsp-config được sử dụng để cấu hình các tham số khác nhau cho các trang JSP. Một số cách sử dụng của nó là:
- Cấu hình thư viện thẻ cho ứng dụng web như sau:
<jsp-config>
<taglib>
<taglib-uri><https://journaldev.com/jsp/tlds/mytags></taglib-uri>
<taglib-location>/WEB-INF/numberformatter.tld</taglib-location>
</taglib>
</jsp-config>
```
- Chúng ta có thể kiểm soát các phần tử scripting trong các trang JSP.
- Chúng ta có thể kiểm soát việc đánh giá JSP Expression Language trong các trang JSP.
- Chúng ta có thể định nghĩa mã hóa trang cho một URL pattern.
- Để định nghĩa kích thước bộ đệm được sử dụng trong đối tượng `out` của trang JSP.
- Để chỉ định rằng nhóm tài nguyên khớp với URL pattern là các tài liệu JSP, và do đó phải được hiểu là các tài liệu XML.
### 31. Làm thế nào để bỏ qua việc đánh giá biểu thức EL trong một JSP?
Chúng ta có thể bỏ qua việc đánh giá EL trong trang JSP bằng hai cách:
1. Sử dụng page directive như `<%@ page isELIgnored="true" %>`.
2. Cấu hình trong web.xml - đây là cách tiếp cận tốt hơn khi bạn muốn vô hiệu hóa đánh giá EL cho nhiều trang JSP.
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config>
```
30. Khi nào Container sẽ khởi tạo nhiều đối tượng JSP/Servlet?
Nếu chúng ta có nhiều phần tử servlet và servlet-mapping trong deployment descriptor cho một servlet hoặc trang JSP duy nhất, thì container sẽ khởi tạo một đối tượng cho mỗi phần tử và tất cả các thể hiện này sẽ có đối tượng ServletConfig và các tham số khởi tạo riêng. Ví dụ, nếu chúng ta cấu hình một trang JSP duy nhất trong web.xml như sau:
<servlet> <servlet-name>Test</servlet-name> <jsp-file>/WEB-INF/test.jsp</jsp-file> <init-param> <param-name>test</param-name> <param-value>Test Value</param-value> </init-param> </servlet>
<servlet-mapping> <servlet-name>Test</servlet-name> <url-pattern>/Test.do</url-pattern> </servlet-mapping>
<servlet> <servlet-name>Test1</servlet-name> <jsp-file>/WEB-INF/test.jsp</jsp-file> </servlet>
<servlet-mapping> <servlet-name>Test1</servlet-name> <url-pattern>/Test1.do</url-pattern> </servlet-mapping>
Sau đó chúng ta có thể truy cập cùng một trang JSP với cả hai mẫu URI và cả hai sẽ có các giá trị tham số khởi tạo riêng của chúng.
31. Chúng ta có thể sử dụng JavaScript với các trang JSP không?
Có, tại sao không? Tôi đã thấy một số nhà phát triển bối rối về điều này. Mặc dù JSP là một công nghệ phía máy chủ, nó được sử dụng để tạo ra một phản hồi phía client và chúng ta có thể thêm mã JavaScript hoặc CSS giống như bất kỳ trang HTML nào khác.
32. Làm thế nào chúng ta có thể ngăn chặn việc tạo phiên (session) ngầm định trong JSP?
Theo mặc định, trang JSP sẽ tạo một phiên (session), nhưng đôi khi chúng ta không cần phiên trong trang JSP. Chúng ta có thể sử dụng thuộc tính session của JSP page directive để chỉ thị trình biên dịch không tạo phiên theo mặc định. Giá trị mặc định của nó là true và phiên sẽ được tạo. Để vô hiệu hóa việc tạo phiên, chúng ta có thể sử dụng nó như sau:
<%@ page session=”false” %>
33. Sự khác biệt giữa JspWriter và Servlet PrintWriter là gì?
PrintWriter là đối tượng thực tế chịu trách nhiệm ghi nội dung vào phản hồi. JspWriter sử dụng đối tượng PrintWriter ẩn sau và cung cấp hỗ trợ bộ đệm (buffer support). Khi bộ đệm đầy hoặc được xả (flushed), JspWriter sẽ sử dụng đối tượng PrintWriter để ghi nội dung vào phản hồi.
34. Chúng ta có thể mở rộng công nghệ JSP như thế nào?
Chúng ta có thể mở rộng công nghệ JSP bằng thẻ tùy chỉnh (custom tags) để tránh các phần tử scripting và mã Java trong các trang JSP.
35. Cung cấp một số thực hành tốt nhất (Best Practices) của JSP?
Một số thực hành tốt nhất của JSP là:
- Tránh các phần tử scripting trong các trang JSP. Nếu JSP EL, các phần tử hành động và JSTL không đáp ứng nhu cầu của bạn, hãy tạo các thẻ tùy chỉnh.
- Sử dụng comment đúng cách, sử dụng JSP comments cho mục đích cấp độ mã hoặc gỡ lỗi để chúng không được gửi đến client.
- Tránh bất kỳ logic nghiệp vụ nào trong trang JSP, các trang JSP chỉ nên được sử dụng để tạo phản hồi cho client.
- Vô hiệu hóa việc tạo phiên trong trang JSP nơi bạn không cần nó để có hiệu suất tốt hơn.
- Sử dụng các chỉ thị page, taglib ở đầu trang JSP để dễ đọc hơn.
- Sử dụng include directive hoặc include action đúng cách dựa trên yêu cầu của bạn; include directive tốt cho nội dung tĩnh trong khi include action tốt cho nội dung động và bao gồm tài nguyên tại thời điểm chạy.
- Xử lý ngoại lệ đúng cách bằng cách sử dụng các trang lỗi JSP để tránh gửi phản hồi do container tạo ra trong trường hợp các trang JSP ném ra ngoại lệ trong phương thức dịch vụ.
- Nếu bạn có mã CSS và JavaScript trong các trang JSP, tốt nhất nên đặt chúng trong các tệp riêng biệt và bao gồm chúng trong trang JSP.
- Hầu hết thời gian JSTL là đủ cho nhu cầu của chúng ta; nếu bạn tìm thấy một kịch bản mà nó không đủ, hãy kiểm tra thiết kế ứng dụng của bạn và cố gắng đặt logic vào một servlet sẽ thực hiện xử lý và sau đó thiết lập các thuộc tính để sử dụng trong các trang JSP.