Từ Đặc tả kỹ thuật của JSP 1.2, rất khuyến khích sử dụng Thư viện thẻ tiêu chuẩn (JSTL) trong ứng dụng web của bạn để giúp giảm nhu cầu về các tập lệnh JSP trong các trang của bạn. Các trang sử dụng JSTL, nói chung, dễ đọc và bảo trì hơn.
...
Nếu có thể, hãy tránh các tập lệnh script bất cứ khi nào các thư viện thẻ cung cấp chức năng tương đương. Điều này làm cho các trang dễ đọc và bảo trì hơn, giúp tách biệt logic nghiệp vụ khỏi logic trình bày và sẽ làm cho các trang của bạn dễ dàng phát triển thành các trang theo phong cách JSP 2.0 (Đặc tả của JSP 2.0 hỗ trợ nhưng không nhấn mạnh vào việc sử dụng tập lệnh).
...
Theo tinh thần của việc áp dụng mẫu thiết kế mô hình-khung nhìn-bộ điều khiển (MVC) để giảm sự ghép nối giữa tầng trình bày từ logic nghiệp vụ, không nên sử dụng tập lệnh JSP để viết logic nghiệp vụ. Thay vào đó, scriptlets JSP được sử dụng nếu cần thiết để chuyển đổi dữ liệu (còn được gọi là "đối tượng giá trị") được trả về từ việc xử lý các yêu cầu của máy khách thành định dạng sẵn sàng của máy khách. Thậm chí sau đó, điều này sẽ được thực hiện tốt hơn với một bộ điều khiển phía trước hoặc thẻ tùy chỉnh.
Nếu bạn muốn gọi cùng một mã Java cho mọi yêu cầu, ít hoặc nhiều hơn bất kể trang được yêu cầu, ví dụ: kiểm tra xem người dùng đã đăng nhập chưa, sau đó triển khai bộ lọc và viết mã theo doFilter()
phương thức. Ví dụ:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
} else {
chain.doFilter(request, response); // Logged in, just continue request.
}
}
Khi được ánh xạ trên một trang thích hợp <url-pattern>
bao gồm các trang ưa thích của JSP, thì bạn không cần phải sao chép cùng một đoạn mã của các trang JSP tổng thể.
Nếu bạn muốn gọi một số mã Java để xử lý yêu cầu, ví dụ như tải trước một số danh sách từ cơ sở dữ liệu để hiển thị trong một số bảng, nếu cần dựa trên một số tham số truy vấn, sau đó triển khai một servlet và viết mã theo doGet()
phương thức. Ví dụ:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<Product> products = productService.list(); // Obtain all products.
request.setAttribute("products", products); // Store products in request scope.
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
} catch (SQLException e) {
throw new ServletException("Retrieving products failed!", e);
}
}
Cách này đối phó với các ngoại lệ là dễ dàng hơn. DB không được truy cập ở giữa chế độ hiển thị JSP, nhưng trước khi hiển thị JSP được hiển thị. Bạn vẫn có thể thay đổi phản hồi mỗi khi truy cập DB ném ngoại lệ. Trong ví dụ trên, mặc định trang lỗi 500 sẽ được hiển thị mà bạn anyway có thể tùy chỉnh bằng một <error-page>
trong web.xml
.
Nếu bạn muốn gọi một số mã Java để xử lý một yêu cầu, ví dụ như xử lý một biểu mẫu gửi, sau đó triển khai một servlet và viết mã theo doPost()
phương thức. Ví dụ:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
response.sendRedirect("home"); // Redirect to home page.
} else {
request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
}
}
Cách này xử lý các đích của trang kết quả khác nhau dễ dàng hơn: hiển thị lại biểu mẫu có lỗi xác thực trong trường hợp có lỗi (trong ví dụ cụ thể này bạn có thể hiển thị lại bằng cách sử dụng ${message}
trong EL ) hoặc chỉ đưa đến trang đích mong muốn trong trường hợp thành công.
Nếu bạn muốn gọi một số mã Java để điều khiển kế hoạch thực hiện và / hoặc đích của yêu cầu và phản hồi, thì hãy triển khai một servlet theo Mẫu điều khiển trước của MVC . Ví dụ:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
} else {
response.sendRedirect(view);
}
} catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
Hoặc chỉ cần áp dụng một khung công tác MVC như JSF , Spring MVC , Wicket , v.v. để bạn kết thúc chỉ với một trang JSP / Facelets và một lớp JavaBean mà không cần một servlet tùy chỉnh.
Nếu bạn muốn gọi một số mã Java để kiểm soát luồng bên trong trang JSP, thì bạn cần phải lấy một thẻ điều khiển luồng (hiện có) như lõi JSTL . Ví dụ: hiển thị List<Product>
trong bảng:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.name}</td>
<td>${product.description}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</table>
Với các thẻ kiểu XML phù hợp độc đáo giữa tất cả các HTML đó, mã có thể đọc được tốt hơn (và do đó có thể duy trì tốt hơn) so với một loạt các tập lệnh với các dấu ngoặc mở và đóng khác nhau ( "Cái niềng răng đóng này thuộc về đâu?" ). Một trợ giúp dễ dàng là định cấu hình ứng dụng web của bạn để đưa ra một ngoại lệ bất cứ khi nào scriptlets vẫn được sử dụng bằng cách thêm đoạn sau vào web.xml
:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
Trong Facelets , sự kế thừa của JSP, mà là một phần của Java EE cung cấp MVC framework JSF , nó đã không thể sử dụng scriptlets . Bằng cách này, bạn sẽ tự động bị buộc phải làm những việc "đúng cách".
Nếu bạn muốn gọi một số mã Java để truy cập và hiển thị dữ liệu "phụ trợ" bên trong trang JSP, thì bạn cần sử dụng EL (Ngôn ngữ biểu thức), những ${}
thứ đó. Ví dụ: hiển thị lại các giá trị đầu vào đã gửi:
<input type="text" name="foo" value="${param.foo}" />
Các ${param.foo}
hiển thị kết quả của request.getParameter("foo")
.
Nếu bạn muốn gọi một số mã Java tiện ích trực tiếp trong trang JSP (thường là public static
các phương thức), thì bạn cần định nghĩa chúng là các hàm EL. Có một chức năng tiêu chuẩn taglib trong JSTL, nhưng bạn cũng có thể dễ dàng tự tạo các chức năng . Dưới đây là một ví dụ về cách JSTL fn:escapeXml
hữu ích để ngăn chặn các cuộc tấn công XSS .
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
Lưu ý rằng độ nhạy XSS hoàn toàn không liên quan đến Java / JSP / JSTL / EL / bất cứ điều gì, vấn đề này cần được tính đến trong mọi ứng dụng web bạn phát triển. Vấn đề của scriptlets là nó không cung cấp cách ngăn chặn dựng sẵn, ít nhất là không sử dụng API Java tiêu chuẩn. Facelets kế thừa của JSP đã ẩn HTML, vì vậy bạn không cần phải lo lắng về các lỗ XSS trong Facelets.