Làm thế nào để tránh mã Java trong các tệp tin JSP?


1673

Tôi mới biết về Java EE và tôi biết rằng một số thứ như ba dòng sau

<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>

là một cách mã hóa trường học cũ và trong phiên bản 2 có tồn tại một phương thức để tránh mã Java trong các tệp tin JSP. Ai đó có thể vui lòng cho tôi biết các dòng JSP 2 thay thế không, và kỹ thuật này được gọi là gì?


22
@Koray Tugay, miễn là biến đếm được khai báo ở đâu đó trước khi sử dụng, thì nó chắc chắn là hợp lệ ...
Sheldon R.

@SheldonR. Điều này hợp lệ: <% = counter ++%> hoặc cái này: <%! int truy cập = 0; int x = bộ đếm ++; %> nhưng không: <%! int truy cập = 0; truy cập ++; %>
Koray Tugay

@KorayTugay, ý tôi là nếu bộ đếm biến được khai báo trong một khối script trước đó, nó sẽ hợp lệ trong một khối sau. Nhưng cuối cùng, các lập trình viên J2EE ngày nay nên sử dụng các biến EL thay vì scriptlets, ...
Sheldon R.

Câu trả lời:


1972

Việc sử dụng scriptlets (những <% %>thứ đó) trong JSP thực sự không được khuyến khích kể từ khi ra đời các taglib (như JSTL ) và EL ( Ngôn ngữ biểu hiện , những thứ đó${} thứ đó) từ năm 2001.

Những nhược điểm chính của scriptlets là:

  1. Tái sử dụng: bạn không thể sử dụng lại scriptlets.
  2. Khả năng thay thế: bạn không thể làm cho scriptlets trừu tượng.
  3. Khả năng OO: bạn không thể sử dụng tính kế thừa / thành phần.
  4. Khả năng gỡ lỗi: nếu scriptlet ném một nửa ngoại lệ, tất cả những gì bạn nhận được là một trang trống.
  5. Khả năng kiểm tra: năng kiểm tra scriptlets không phải là đơn vị kiểm tra.
  6. Khả năng bảo trì: mỗi saldo cần thêm thời gian để duy trì logic mã hỗn hợp / lộn xộn / trùng lặp.

Sun Oracle chính nó cũng khuyến cáo trong JSP mã hóa quy ước để tránh sử dụng scriptlets bất cứ khi nào chức năng tương tự là có thể bằng cách (tag) các lớp học. Dưới đây là một số trích dẫn liên quan:

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.


Làm thế nào để thay thế scriptlets hoàn toàn phụ thuộc vào mục đích duy nhất của mã / logic. Thông thường, mã này sẽ được đặt trong một lớp Java đầy đủ:

  • 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 staticcá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:escapeXmlhữ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.

Xem thêm:


117
+1 Câu trả lời tuyệt vời. Nhưng đừng giáo điều, đôi khi sử dụng scriptlets là ok, nhưng đó phải là ngoại lệ chứng minh quy tắc.
Svachon

26
@svachon: Scriptlets rất hữu ích cho việc tạo mẫu / thử nghiệm nhanh. Theo như tôi biết, chỉ có một cách sử dụng "hợp pháp" sản xuất tập lệnh, cụ thể là <% response.getWriter().flush(); %>giữa </head><body>để cải thiện hiệu suất phân tích trang web trong trình duyệt web. Nhưng việc sử dụng này lần lượt hoàn toàn không đáng kể khi kích thước bộ đệm đầu ra ở phía máy chủ thấp (1 ~ 2KB). Xem thêm bài viết này .
BalusC

5
@BalusC Một vài lần tôi đã bị mắc kẹt với các lớp java không theo mô hình getter / setter. IMHO đó là một trường hợp mà một scripltet thực hiện công việc.
Svachon

41
@svachon: Tôi sẽ bọc các lớp đó bằng các lớp javabean riêng và sử dụng chúng thay thế.
BalusC

31
Đó là một câu trả lời khá hay, nhưng các phần doGet và doPost lại gây hiểu nhầm. Các phương thức này là để xử lý các phương thức yêu cầu cụ thể (CHÍNH, NHẬN và POST) và không dành cho các yêu cầu "tiền xử lý" hoặc "hậu xử lý"!
MetroidFan2002

225

Như một biện pháp bảo vệ: Vô hiệu hóa Scriptlets cho tốt

Khi một câu hỏi khác đang thảo luận, bạn có thể và luôn luôn nên vô hiệu hóa tập lệnh trong bộ web.xmlmô tả ứng dụng web của mình .

Tôi sẽ luôn luôn làm điều đó để ngăn chặn bất kỳ nhà phát triển nào thêm tập lệnh, đặc biệt là trong các công ty lớn hơn, nơi bạn sẽ mất tổng quan sớm hay muộn. Các web.xmlthiết lập trông như thế này:

<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
     <scripting-invalid>true</scripting-invalid>
  </jsp-property-group>
</jsp-config>

4
Điều này cũng vô hiệu hóa bình luận scriptlet?: <%-- comment that i don't want in the final HTML --%>. Tôi thấy nó hữu ích khi sử dụng chúng chứ không phải là nhận xét HTML.
David Lavender

16
@MrSpoon theo dõi một câu trả lời cho bạn. Theo câu trả lời + nhận xét này, điều này sẽ tắt scriptlets <% %>, biểu thức <%! %>scriptlet và khai báo scriptlet <%= %>. Điều đó có nghĩa là các chỉ thị <%@ %>và nhận xét <%-- --%>vẫn được bật và có thể sử dụng được, vì vậy bạn vẫn có thể thực hiện nhận xét và bao gồm.
Martin Carney

3
Việc vô hiệu hóa các chỉ thị scriptlet sẽ rất tệ - khoảng trắng trim là vô giá để tương tác với các hệ thống kế thừa kỳ dị với khoảng trắng thừa.
corsiKa

108

JSTL cung cấp các thẻ cho các điều kiện, vòng lặp, bộ, được, v.v. Ví dụ:

<c:if test="${someAttribute == 'something'}">
   ...
</c:if>

JSTL hoạt động với các thuộc tính yêu cầu - chúng thường được đặt trong yêu cầu bởi một Servlet, chuyển tiếp tới tệp JSP.


2
Tại sao bạn nói JSTL hoạt động với các thuộc tính yêu cầu? Họ có thể làm việc với các thuộc tính trong bất kỳ phạm vi nào, phải không?
Koray Tugay

60

Tôi không chắc chắn nếu tôi làm điều này đúng.

Bạn nên đọc một cái gì đó về MVC. Spring MVC & Struts 2 là hai giải pháp phổ biến nhất.


29
MVC có thể được thực hiện với servlets / jsp bằng nhiều kỹ thuật trên mà không cần Spring hoặc Struts.
stepanian

18
Làm thế nào nó trả lời câu hỏi?
xyz

54

Bạn có thể sử dụng các thẻ JSTL cùng với các biểu thức EL để tránh xen kẽ mã Java và HTML:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
    <head>
    </head>
    <body>

        <c:out value="${x + 1}" />
        <c:out value="${param.name}" />
        // and so on

    </body>
</html>

34

Ngoài ra còn có các khung dựa trên thành phần như Wicket tạo ra rất nhiều HTML cho bạn. Các thẻ kết thúc trong HTML là cực kỳ cơ bản và hầu như không có logic nào bị lẫn vào. Kết quả là các trang HTML gần như trống rỗng với các thành phần HTML điển hình. Nhược điểm là có rất nhiều thành phần trong API Wicket để tìm hiểu và một số điều có thể khó đạt được dưới những ràng buộc đó.


33

Trong mẫu Kiến trúc MVC, các tệp đại diện cho lớp View. Việc nhúng mã java trong các tệp tin được coi là một cách thực hành tồi. Bạn có thể sử dụng JSTL , freeMarker , vận tốc với JSP làm "công cụ mẫu". Nhà cung cấp dữ liệu cho các thẻ đó phụ thuộc vào các khung mà bạn đang xử lý. Struts 2webworknhư là một triển khai cho Mô hình MVC sử dụng OGNL "kỹ thuật rất thú vị để hiển thị Thuộc tính Đậu cho JSP".


27

Kinh nghiệm đã chỉ ra rằng các lỗi của JSP có một số thiếu sót, một trong số đó là khó tránh khỏi việc trộn đánh dấu với mã thực tế.

Nếu bạn có thể, sau đó xem xét sử dụng một công nghệ chuyên dụng cho những gì bạn cần làm. Trong Java EE 6 có JSF 2.0, cung cấp rất nhiều tính năng hay, bao gồm dán các hạt Java cùng với các trang JSF thông qua #{bean.method(argument)}cách tiếp cận.


3
Câu trả lời cũ nhưng tôi không thể cưỡng lại để nói rằng JSF là một trong những phát minh khủng khiếp nhất trong không gian Java. Hãy thử tạo một liên kết (HTTP GET like) và bạn sẽ hiểu lý do tại sao.
Alex

@Alex nhưng vẫn tốt hơn. Hãy giới thiệu một cái gì đó thậm chí còn tốt hơn.
Thorbjørn Ravn Andersen

26

nếu bạn chỉ đơn giản muốn tránh những hạn chế của mã hóa Java trong JSP, bạn có thể làm như vậy ngay cả với các tập lệnh. Chỉ cần tuân theo một số nguyên tắc để có Java tối thiểu trong JSP và hầu như không có tính toán và logic trong trang JSP.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%//instantiate a JSP controller
MyController clr = new MyController(request, response);

//process action if any
clr.process(request);

//process page forwaring if necessary

//do all variable assignment here
String showMe = clr.getShowMe();%>

<html>
    <head>
    </head>
    <body>
        <form name="frm1">
            <p><%= showMe %>
            <p><% for(String str : clr.listOfStrings()) { %>
            <p><%= str %><% } %>

            // and so on   
        </form>
    </body>
</html>

26

Tìm hiểu để tùy chỉnh và viết các thẻ của riêng bạn bằng JSTL

Lưu ý rằng EL là EviL (ngoại lệ thời gian chạy, tái cấu trúc)
Wicket cũng có thể là xấu (hiệu suất, toilsome cho các ứng dụng nhỏ hoặc lớp xem đơn giản)

Ví dụ từ java2s ,

Điều này phải được thêm vào web.xml của ứng dụng web

<taglib>
    <taglib-uri>/java2s</taglib-uri>
    <taglib-location>/WEB-INF/java2s.tld</taglib-location>
</taglib>

tạo tệp: java2s.tld trong / WEB-INF /

<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">

<!-- a tab library descriptor -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
    <tlib-version>1.0</tlib-version>
    <jsp-version>1.2</jsp-version>
    <short-name>Java2s Simple Tags</short-name>

    <!-- this tag manipulates its body content by converting it to upper case
    -->
    <tag>
        <name>bodyContentTag</name>
        <tag-class>com.java2s.BodyContentTag</tag-class>
        <body-content>JSP</body-content>
        <attribute>
          <name>howMany</name>
        </attribute>
    </tag>
</taglib>

biên dịch mã sau vào WEB-INF \ class \ com \ java2s

package com.java2s;

import java.io.IOException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;

public class BodyContentTag extends BodyTagSupport{
    private int iterations, howMany;

    public void setHowMany(int i){
        this.howMany = i;
    }

    public void setBodyContent(BodyContent bc){
        super.setBodyContent(bc);
        System.out.println("BodyContent = '" + bc.getString() + "'");
    }

    public int doAfterBody(){
        try{    
            BodyContent bodyContent = super.getBodyContent();
            String bodyString  = bodyContent.getString();
            JspWriter out = bodyContent.getEnclosingWriter();

            if ( iterations % 2 == 0 ) 
                out.print(bodyString.toLowerCase());
            else
                out.print(bodyString.toUpperCase());

            iterations++;
            bodyContent.clear(); // empty buffer for next evaluation
        }
        catch (IOException e) {
            System.out.println("Error in BodyContentTag.doAfterBody()" + e.getMessage());
            e.printStackTrace();
        } // end of catch

        int retValue = SKIP_BODY;

        if ( iterations < howMany ) 
            retValue = EVAL_BODY_AGAIN;

        return retValue;
    }
}

Khởi động máy chủ và tải bodyContent.jsp trong trình duyệt

<%@ taglib uri="/java2s" prefix="java2s" %>
<html>
    <head>
        <title>A custom tag: body content</title>
    </head>
    <body>
        This page uses a custom tag manipulates its body content.Here is its output:
        <ol>
            <java2s:bodyContentTag howMany="3">
            <li>java2s.com</li>
            </java2s:bodyContentTag>
        </ol>
    </body>
</html>

mặc dù khả năng sử dụng lại các thành phần vẫn ổn nhưng nó nhắm vào một số lĩnh vực
tomasb

25

Wicket cũng là một giải pháp thay thế hoàn toàn tách java khỏi html, do đó, một nhà thiết kế và lập trình viên có thể làm việc cùng nhau và trên các bộ mã khác nhau mà ít hiểu biết về nhau.

Nhìn vào Wicket.


23

Bạn đã đưa ra một câu hỏi hay và mặc dù bạn đã có câu trả lời tốt, tôi sẽ đề nghị bạn thoát khỏi JSP. Đó là công nghệ lỗi thời mà cuối cùng sẽ chết. Sử dụng một cách tiếp cận hiện đại, như động cơ mẫu. Bạn sẽ phân tách rõ ràng các lớp trình bày và doanh nghiệp và chắc chắn không có mã Java trong các mẫu, do đó bạn có thể tạo các mẫu trực tiếp từ phần mềm chỉnh sửa bản trình bày web, trong hầu hết các trường hợp sử dụng WYSIWYG.

Và chắc chắn tránh xa các bộ lọc và xử lý trước và sau, nếu không bạn có thể xử lý các khó khăn hỗ trợ / gỡ lỗi vì bạn luôn không biết biến đó lấy giá trị ở đâu.


9
Bản thân JSP là một công cụ mẫu
WarFox

1
-1 - Có nhiều lý do hoàn toàn hợp lệ để sử dụng bộ lọc, bộ xử lý trước và bộ xử lý sau. Vâng, bạn có thể kết thúc với các giá trị có vẻ bí ẩn, nhưng không nếu bạn hiểu kiến ​​trúc của bạn.
RustyTheBoyRobot

21

để tránh mã java trong các tệp tin java, java hiện cung cấp các thư viện thẻ như JSTL, java cũng đã đưa ra JSF để bạn có thể viết tất cả các cấu trúc lập trình dưới dạng thẻ


21

Cho dù bạn cố gắng tránh bao nhiêu, khi bạn làm việc với các nhà phát triển khác, một số người trong số họ vẫn sẽ thích scriptlet và sau đó chèn mã ác vào dự án. Do đó, thiết lập dự án ở dấu hiệu đầu tiên là rất quan trọng nếu bạn thực sự muốn giảm mã scriptlet. Có một số kỹ thuật để vượt qua điều này (bao gồm một số khung mà các đề cập khác). Tuy nhiên, nếu bạn thích cách thuần túy hơn, thì hãy sử dụng tệp thẻ JSTL. Điều thú vị ở đây là bạn cũng có thể thiết lập các trang chính cho dự án của mình, vì vậy các trang khác có thể kế thừa các trang chính

Tạo một trang chính được gọi là base.tag trong các thẻ WEB-INF / của bạn với nội dung sau

<%@tag description="Overall Page template" pageEncoding="UTF-8"%>

<%@attribute name="title" fragment="true" %>

<html>
  <head>
    <title>  
       <jsp:invoke fragment="title"></jsp:invoke>
    </title>

  </head>
  <body>
    <div id="page-header">
       ....
    </div>
    <div id="page-body">
      <jsp:doBody/>
    </div>
    <div id="page-footer">
      .....
    </div>
  </body>
</html>

Trên trang mater này, tôi đã tạo một đoạn gọi là "title", để trong trang con, tôi có thể chèn thêm mã vào vị trí này của trang chính. Ngoài ra, thẻ <jsp:doBody/>sẽ được thay thế bằng nội dung của trang con

Tạo trang con (child.jsp) trong thư mục WebContent của bạn:

<%@ taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:base>
    <jsp:attribute name="title"> 
        <bean:message key="hello.world" />
    </jsp:attribute>

    <jsp:body>
    [Put your content of the child here]
    </jsp:body>   
</t:base>

<t:base>được sử dụng để chỉ định trang chính bạn muốn sử dụng (đó là base.tag tại thời điểm này). Tất cả nội dung bên trong thẻ <jsp:body>ở đây sẽ thay thế <jsp:doBody/>trên trang chính của bạn. Trang con của bạn cũng có thể bao gồm bất kỳ thẻ lib nào và bạn có thể sử dụng nó bình thường như các đề cập khác. Tuy nhiên, nếu bạn sử dụng bất kỳ mã scriptlet nào tại đây ( <%= request.getParameter("name") %>...) và thử chạy trang này, bạn sẽ nhận được a JasperException because Scripting elements ( &lt;%!, &lt;jsp:declaration, &lt;%=, &lt;jsp:expression, &lt;%, &lt;jsp:scriptlet ) are disallowed here. Do đó, không có cách nào người khác có thể đưa mã ác vào tệp jsp

Gọi trang này từ bộ điều khiển của bạn:

Bạn có thể dễ dàng gọi tệp child.jsp từ bộ điều khiển của mình. Điều này cũng hoạt động tốt với khung struts


"Cho dù bạn cố gắng tránh bao nhiêu, khi bạn làm việc với các nhà phát triển khác, một số trong số họ vẫn sẽ thích scriptlet và sau đó chèn mã ác vào dự án." Xem câu trả lời "Như một biện pháp bảo vệ: Vô hiệu hóa Scriptlets For Good".
Lluis Martinez


18

Chỉ cần sử dụng thẻ JSTL và biểu thức EL.


17

Nếu ai đó thực sự chống lại lập trình bằng nhiều ngôn ngữ , tôi đề nghị GWT, về mặt lý thuyết bạn có thể tránh tất cả các yếu tố JS và HTML, vì Google Toolkit chuyển đổi tất cả máy khách và mã được chia sẻ thành JS, vì vậy bạn sẽ không gặp vấn đề gì với chúng, vì vậy bạn có một dịch vụ web mà không cần mã hóa bằng bất kỳ ngôn ngữ nào khác. Thậm chí bạn có thể sử dụng một số CSS mặc định từ một nơi nào đó vì nó được cung cấp bởi các tiện ích mở rộng (smartGWT hoặc Vaadin). Bạn không cần phải học hàng tá chú thích.

Tất nhiên, nếu bạn muốn, bạn có thể tự hack sâu vào mã và tiêm mã JS và làm phong phú trang HTML của mình, nhưng thực sự bạn có thể tránh nó nếu muốn, và kết quả sẽ tốt như được viết trong bất kỳ khuôn khổ nào khác. Tôi nói rằng đáng để thử, và GWT cơ bản là tài liệu tốt.

Và tất nhiên, nhiều lập trình viên đồng nghiệp đã mô tả hoặc đề xuất một số giải pháp khác. GWT dành cho những người thực sự không muốn đối phó với phần web hoặc để tối thiểu hóa nó.


1
Không thực sự trả lời câu hỏi của OP.
Evan Donovan

1
@EvanDonovan tốt, thực tế nó không đưa ra câu trả lời. Bạn không cần phải lộn xộn với các mã Java trộn lẫn với các ngôn ngữ khác. Tôi thừa nhận nó sử dụng Java để mã hóa, nhưng nó sẽ được dịch sang JS mà không cần các cuộc gọi Java. Nhưng phạm vi của câu hỏi là làm thế nào để tránh sự hỗn loạn của JSP cổ điển. Và công nghệ GWT giải quyết điều đó. Tôi đã thêm câu trả lời này vì không ai đề cập đến nó, nhưng có liên quan vì nó là một thay thế cho JSP. Tôi không muốn trả lời toàn bộ phạm vi câu hỏi, nhưng để thêm một thông tin có giá trị cho những người đang tìm kiếm giải pháp thay thế.
CsBalazsHungary

16

Một ý tưởng gọn gàng từ thế giới Python là các ngôn ngữ thuộc tính Mẫu ; TAL được giới thiệu bởi Zope (do đó còn gọi là "Mẫu trang Zope", ZPT) và là một tiêu chuẩn, với các triển khai trong PHP, XSLT và Java (Tôi đã sử dụng các hóa thân Python / Zope và PHP). Trong lớp ngôn ngữ tạo khuôn mẫu này, một ví dụ ở trên có thể trông như thế này:

<table>
    <tr tal:repeat="product products">
        <td tal:content="product/name">Example product</td>
        <td tal:content="product/description">A nice description</td>
        <td tal:content="product/price">1.23</td>
    </tr>
</table>

Mã này trông giống như HTML thông thường (hoặc XHTML) cộng với một số thuộc tính đặc biệt trong không gian tên XML; nó có thể được xem bằng trình duyệt và được chỉnh sửa một cách an toàn bởi một nhà thiết kế. Có hỗ trợ cho các macro và cho i18n:

<h1 i18n:translate="">Our special offers</h1>
<table>
    <tr tal:repeat="product products">
        <td tal:content="product/name"
            i18n:translate="">Example product</td>
        <td tal:content="product/description"
            i18n:translate="">A nice description</td>
        <td tal:content="product/price">1.23</td>
    </tr>
</table>

Nếu bản dịch của nội dung có sẵn, chúng được sử dụng.

Mặc dù vậy, tôi không biết nhiều về việc triển khai Java .


1
Kể từ tháng 12 năm 2009, JSP đã thành công nhờ Facelets hỗ trợ công cụ này. Facelets cũng dựa trên XML. Xem thêm trong số những người khác, chương Facelets trong hướng dẫn Java EE 6ui:xxxcác thẻ trong Facelts VDL .
BalusC

Tôi không biết rõ về Facelets, nhưng IIRC hoàn toàn là về việc viết các lớp thực hiện các phần tử XML tùy chỉnh. Cách TAL / ZPT là có các mẫu chứa HTML (X) đúng với các thuộc tính đặc biệt điền hoặc thay thế các phần tử gốc; do đó, bạn có thể xem mẫu làm việc và xem một nguyên mẫu có nội dung giả đẹp. Tôi không chắc chắn Facelets cho phép điều chỉnh các thành phần HTML gốc (không có không gian tên bổ sung) bằng các thuộc tính tùy chỉnh.
Tobias

Tôi chỉ có một cái nhìn khác về công cụ Facelets này. Nó chứa tất cả các loại phương tiện xác nhận, vv và do đó tuân theo một triết lý hoàn toàn khác so với TAL. Cách TAL là, "Giữ logic ra khỏi khuôn mẫu càng sạch càng tốt; có tất cả những thứ phức tạp được thực hiện bởi bộ điều khiển cung cấp cho nó." Bạn sẽ không bao giờ đưa mẫu Facelets cho nhà thiết kế để anh ấy / cô ấy chỉnh nó; nó chỉ là không thể Về nội dung được tạo - nó giống như sử dụng tal:replace="structure (expression)"các thuộc tính mọi lúc.
Tobias


14

Chắc chắn, thay thế <%! counter++; %>bằng kiến ​​trúc nhà sản xuất sự kiện - người tiêu dùng, nơi lớp doanh nghiệp được thông báo về sự cần thiết phải tăng bộ đếm, nó phản ứng tương ứng và thông báo cho người thuyết trình để họ cập nhật quan điểm. Một số giao dịch cơ sở dữ liệu có liên quan, vì trong tương lai chúng ta sẽ cần biết giá trị mới và cũ của bộ đếm, người đã tăng nó và với mục đích gì. Rõ ràng là tuần tự hóa có liên quan, vì các lớp hoàn toàn tách rời. Bạn sẽ có thể tăng bộ đếm của mình qua RMI, IIOP, SOAP. Nhưng chỉ HTML là bắt buộc, mà bạn không thực hiện, vì đó là một trường hợp trần tục như vậy. Mục tiêu mới của bạn là đạt 250 gia số một giây trên máy chủ RAM E7, 64GB sáng bóng mới của bạn.

Tôi đã có hơn 20 năm lập trình, hầu hết các dự án đều thất bại trước sextet: Khả năng tái sử dụng Khả năng tái sử dụng Khả năng gỡ lỗi Khả năng gỡ lỗi Khả năng duy trì khả năng duy trì thậm chí còn cần thiết. Các dự án khác, được điều hành bởi những người chỉ quan tâm đến chức năng, đã cực kỳ thành công. Ngoài ra, cấu trúc đối tượng cứng, được triển khai quá sớm trong dự án, làm cho mã không thể thích ứng với những thay đổi mạnh mẽ trong các thông số kỹ thuật (còn gọi là nhanh nhẹn).

Vì vậy, tôi coi như sự trì hoãn hoạt động xác định "lớp" hoặc cấu trúc dữ liệu dư thừa ngay từ đầu trong dự án hoặc khi không được yêu cầu cụ thể.  


11

Về mặt kỹ thuật, tất cả các tệp được chuyển đổi thành Servlets trong thời gian chạy . Ban đầu, JSP được tạo ra với mục đích tách rời logic nghiệp vụ và logic thiết kế, theo mô hình MVC. Vì vậy, về mặt kỹ thuật, tất cả các mã java trong thời gian chạy. Nhưng để trả lời câu hỏi, Thư viện thẻ thường được sử dụng để áp dụng logic (loại bỏ mã Java) cho các trang JSP.


8

Nếu chúng ta sử dụng những điều sau đây trong một ứng dụng web java, mã java có thể được loại bỏ khỏi tiền cảnh của JSP.

  1. Sử dụng kiến ​​trúc MVC cho ứng dụng web

  2. Sử dụng thẻ JSP

    a. Thẻ tiêu chuẩn

    b. Thẻ tùy chỉnh

  3. Ngôn ngữ biểu hiện


8

Làm thế nào để tránh mã Java trong các tệp tin JSP?

Bạn có thể sử dụng các thẻ thư viện tab như JSTL ngoài Ngôn ngữ biểu thức ( EL ). Nhưng EL không hoạt động tốt với JSP. Vì vậy, tốt hơn hết là bỏ hoàn toàn JSP và sử dụng Facelets .

Facelets là ngôn ngữ khai báo trang không phải là trang đầu tiên được thiết kế cho JSF (Java Server Faces) , cung cấp một mô hình lập trình đơn giản và mạnh mẽ hơn cho các nhà phát triển JSF so với JSP. Nó giải quyết các vấn đề khác nhau xảy ra trong JSP để phát triển ứng dụng web.

nhập mô tả hình ảnh ở đây

Nguồn


Tôi chắc chắn thứ hai phản ứng này. JSF có hoặc không có Facelets. Tôi nghĩ rằng việc phát triển trong JSP phần lớn đã chấm dứt hơn 10 năm trước. Lần cuối cùng tôi viết bài viết vào năm 2000!

4

Sử dụng Scriptlets là một cách rất cũ và Không được khuyến khích. Nếu bạn muốn trực tiếp xuất nội dung nào đó trong các trang JSP của mình, chỉ cần sử dụng Ngôn ngữ biểu thức (EL) cùng với JSTL .

Ngoài ra còn có các tùy chọn khác như sử dụng một công cụ tạo khuôn mẫu như Velocity, Freemarker, Thymeleaf, v.v.

Ngoài ra, hãy lưu ý rằng đó không phải là cách tốt nhất để thực hiện logic nghiệp vụ trong lớp xem, bạn nên thực hiện các logic nghiệp vụ của mình trong lớp Dịch vụ và chuyển kết quả đầu ra cho các khung nhìn của bạn thông qua Bộ điều khiển.


3

Không có gì trong số đó được sử dụng nữa bạn ạ, lời khuyên của tôi là tách rời chế độ xem (css, html, javascript, v.v.) khỏi máy chủ.

Trong trường hợp của tôi, tôi thực hiện các hệ thống của mình xử lý chế độ xem bằng Angular và mọi dữ liệu cần thiết được đưa từ máy chủ sử dụng các dịch vụ còn lại.

Tin tôi đi, điều này sẽ thay đổi cách bạn thiết kế


3

Sử dụng xương sống, góc cạnh như khung javascript để thiết kế giao diện người dùng và tìm nạp dữ liệu bằng phần còn lại api. Điều này sẽ loại bỏ hoàn toàn sự phụ thuộc java khỏi UI.


3

JSP 2.0 có một tính năng gọi là "Thẻ tập tin" , bạn có thể viết các thẻ mà không cần javamã bên ngoài và tld. Bạn cần tạo một .tagtệp và đặt nó vào, WEB-INF\tagsthậm chí bạn có thể tạo cấu trúc thư mục để đóng gói các thẻ của mình.

Ví dụ:

/WEB-INF/tags/html/label.tag

<%@tag description="Rensders a label with required css class" pageEncoding="UTF-8"%>
<%@attribute name="name" required="true" description="The label"%>

<label class="control-label control-default"  id="${name}Label">${name}</label>

Sử dụng nó như

<%@ taglib prefix="h" tagdir="/WEB-INF/tags/html"%>
<h:label  name="customer name" />

Ngoài ra, bạn có thể đọc thân thẻ dễ dàng

/WEB-INF/tags/html/bold.tag
<%@tag description="Bold tag" pageEncoding="UTF-8"%>
<b>
  <jsp:doBody/>
</b>

Sử dụng nó

<%@ taglib prefix="h" tagdir="/WEB-INF/tags/bold"%>
<h:bold>Make me bold</h:bold>

Các mẫu rất đơn giản nhưng bạn có thể thực hiện nhiều nhiệm vụ phức tạp ở đây. Vui lòng xem xét bạn có thể sử dụng các thẻ khác (ví dụ: JSTLcó các thẻ kiểm soát như if/forEcah/chosenthao tác văn bản như format/contains/uppercasehoặc thậm chí các thẻ SQL select/update), vượt qua tất cả các tham số loại, ví dụ: Hashmapquyền truy cập session,request ... trong tập tin thẻ của bạn quá.

Thẻ tệp được phát triển dễ dàng vì bạn không cần phải khởi động lại máy chủ khi thay đổi chúng, như các tệp JSP. Điều này làm cho chúng dễ dàng để phát triển.

Ngay cả khi bạn sử dụng một khung như Struts 2, có rất nhiều thẻ tốt, bạn có thể thấy rằng việc có các thẻ của riêng bạn có thể làm giảm mã của bạn rất nhiều. Bạn có thể chuyển tham số thẻ của mình cho thanh chống và cách này tùy chỉnh thẻ khung của bạn.

Bạn có thể sử dụng thẻ không chỉ để tránh java mà còn giảm thiểu mã HTML của bạn. Bản thân tôi cố gắng xem lại mã HTML và xây dựng thẻ rất nhiều ngay khi thấy các bản sao mã bắt đầu trong các trang của mình.

(Ngay cả khi bạn kết thúc bằng cách sử dụng java trong mã JSP của mình, điều mà tôi hy vọng là không, bạn có thể gói mã đó trong một thẻ)


1

Như nhiều câu trả lời, hãy sử dụng JSTL hoặc tạo các thẻ tùy chỉnh của riêng bạn. Đây là lời giải thích tốt về việc tạo thẻ tùy chỉnh


1
  1. Tạo các giá trị và tham số của bạn bên trong các lớp servlet của bạn
  2. Tìm nạp các giá trị và tham số đó trong tệp JSP của bạn bằng JSTL / Taglib

Điểm hay của phương pháp này là mã của bạn cũng giống như mã HTML!


0

Bằng cách sử dụng các thẻ JSTL cùng với biểu thức EL, bạn có thể tránh điều này. Đặt những điều sau đây trong trang jsp của bạn:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.