1. 程式人生 > 其它 >JSP(Java Server Pages “Java伺服器端頁面”)

JSP(Java Server Pages “Java伺服器端頁面”)

JSP(Java Server Pages “Java伺服器端頁面”)

JSP簡介

JSP全稱是Java Server Pages,是一種動態網頁技術,JSP其實就是在html中插入了java程式碼和JSP標籤之後形成的檔案,檔名以.jsp結尾。其實JSP就是一個servlet。
在servlet中編寫html比較痛苦,而寫JSP就像在寫html,但它相比html而言,html只能為使用者提供靜態資料即靜態頁面,而Jsp技術允許在頁面中巢狀java程式碼,為使用者提供動態資料,從而形成動態頁面

需要注意的是最好只在JSP中編寫動態輸出的java程式碼。

JSP原理

假設存在一個jsp頁面叫a.jsp,則

  1. 當瀏覽器第一次訪問a.jsp的時候,會被伺服器翻譯成a_jsp.java ,
  2. jdk將a_jsp.java編譯成a_jsp.class檔案 , 執行class中的程式碼,給瀏覽器進行響應
  3. 當瀏覽器再次訪問a.jsp的時候,如果class已經存在就不在翻譯而是直接執行

JSP的執行機制

將JSP檔案轉換為.java檔案並將其編譯為.class檔案的過程都是由tomcat完成的,在tomcat內部有一個翻譯引擎,當JSP頁面第一次被訪問時由翻譯引擎轉換為.java檔案並編譯出.class檔案。之後再執行該class檔案。
在JSP中的html程式碼都會翻譯到servlet中的out.write()中。

執行過程:

  1. 當Web容器接收到使用者的第一個jsp頁面請求時,jsp引擎將這個jsp頁面轉換為java原始碼(Java Servlet源程式),若在轉換過程中發現jsp檔案中有任何語法錯誤,轉換過程將中斷,並向伺服器和客戶端返回錯誤資訊。
  2. 轉換成功後,jsp引擎用javac將java原始碼編譯成相應的位元組碼檔案*.class(一個Servlet)。然後由Servlet容器處理。
  3. Servlet容器載入*.class檔案,建立該Servlet例項,並執行Servlet的jspInit()方法(該方法在Servlet整個生命週期中只執行一次。它的作用是可以在其裡面進行一些初始化設定,諸如建立與資料庫的連線、建立網路連線、獲取配置檔案的引數等)。
  4. 執行_jspService()方法來處理客戶端的請求。對於每一個請求,JSP引擎都會建立一個新的執行緒來處理。
  5. 如果.jsp檔案被修改了,則伺服器會根據設定決定是否對該檔案重新編譯,如果需要重新編譯則將編譯後的結果取代記憶體中的Servlet,並繼續上述過程。
  6. 雖然JSP的效率很高,但在第一次呼叫是往往由於需要轉換和編譯過程而產生一些輕微的延遲。此外,可能由於系統資源不足等原因,JSP容器會以某種不確定的方式將Servlet從記憶體中移去。在這種情況下,將會呼叫jspServlet()方法進行清除工作,接著Servlet例項便被加入到“垃圾收集”收集。
  7. 當請求處理完成後,響應物件由JSP容器接受,並將HTML格式的響應資訊傳送回客戶端。

當你檢視jsp檔案被伺服器翻譯成的 _jsp.java檔案時,可以發現 _jsp.java這個類,它繼承了HttpJspBase類,而HttpJspBase類又繼承了HttpServlet類,故而jsp本質就是一個Servlet

JSP類中有三個重要的方法

//初始化jsp
public void _jspInit() {
}
//銷燬jsp
public void _jspDestroy() {
}
//jspService
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
        throws java.io.IOException, javax.servlet.ServletException {

    if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
        final java.lang.String _jspx_method = request.getMethod();
        if ("OPTIONS".equals(_jspx_method)) {
            response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
            return;
        }
        if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
            response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
            response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允許 GET、POST 或 HEAD。Jasper 還允許 OPTIONS");
            return;
        }
    }

JSP類中內建的一些物件

final javax.servlet.jsp.PageContext pageContext;//頁面上下文
javax.servlet.http.HttpSession session = null;//session
final javax.servlet.ServletContext application;//applicationContext
final javax.servlet.ServletConfig config;//config
javax.servlet.jsp.JspWriter out = null;//out  輸出
final java.lang.Object page = this; //page  當前頁面
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
//由於繼承了HttpServlet,肯定有請求和響應物件
HttpServletRequest
HttpServletResponse

以上的物件可以在jsp頁面中直接使用

在JSP頁面中:

只要是java程式碼就會原封不動輸出

如果是html文字,就會轉化成 out.write()型別,輸出到前端

例如:

out.write("<html>\n");

JSP基礎語法

任何語言都有自己的語法,JSP作為java技術的一種應用,自然支援java所有語法,同時其也擁有一些擴充的語法

1.<%= %>  <%--jsp表示式--%>
2.<% %>   <%--jsp指令碼片段--%>
3.<%! %>  <%--jsp宣告--%>
4.<%--jsp的註釋--%>

關於JSP的註釋和HTML的註釋的區別:JSP的註釋不會在客戶端顯示,而HTML的註釋是可以顯示在客戶端的。(即使用者通過瀏覽器檢視網頁原始碼時,看不到JSP的註釋,卻可以看到HTML的註釋)

JSP表示式

<%--jsp表示式
作用:將程式的結果輸出到客戶端
<%= 變數或表示式%>
--%>
<%=new Date() %>

JSP指令碼片段

<%--jsp指令碼片段--%>
<%
  int sum = 0;
  for (int i = 0; i <= 100; i++) {
    sum+=i;
  }
  out.print("<h1>sum="+sum+"<h1>");
%>
<%--在程式碼中嵌入html元素--%>
  <%
    for (int i = 0; i < 5; i++) {
  %>
  <h1> Hello,World <%= i%></h1>
  <%
    }
  %>

JSP宣告

<%--jsp宣告,JSP宣告用於定義JSP中的變數、方法以及靜態方法,實際上相當於java類中定義一個全域性變數或方法--%>
  <%!
    static {
      System.out.println("Loading Servlet");
    }

    private int globalVar = 0;
    public void yue(){
      System.out.println("進入方法yue");
    }
  %>

jsp宣告中的程式碼塊在jsp被編譯成java類時,直接被翻譯為該類的全域性變數,而其他的,比如jsp表示式,jsp指令碼片段則被翻譯在_jspService( )方法內

JSP指令

page指令

定義JSP檔案的全域性屬性,描述了與頁面相關的資訊,作用域為所在的JSP頁面和其包含的檔案,同一個JSP頁面可以有多個page屬性:<%@page %>,其屬性除了import之外其他的只能使用一次。

<%@page args... %>

inclue指令

用於在當前JSP頁面中載入需要插入的檔案程式碼,即為頁面插入一個靜態檔案,如JSP頁面、HTML頁面、文字檔案或一段Java程式,這些載入的程式碼和原有的JSP程式碼合併成一個新的JSP檔案;常見的有網站所有頁面的共同頁面
格式為:

<%@include file=”檔名”%>

Include指令只有一個file屬性
例:讓網頁頭尾顯示公有頁面

<%--jsp指令
%@include file= 將多個頁面合起來變成一個頁面
--%>
<%@include file="common/header.jsp"%>
<h1>
    網頁主體
</h1>
<%@include file="common/footer.jsp"%>
<hr>

也可使用JSP標籤的方式實現同樣的效果:

<%--jsp標籤
jsp:include  拼接頁面,本質是三個頁面,只是從jsp翻譯成的java類中的靜態資源呼叫進行拼接
--%>
<jsp:include page="common/header.jsp"/>
<h1>
    網頁主體2
</h1>
<jsp:include page="common/footer.jsp"/>
<%--標籤耦合性低,用的較多--%>

Include指令由於是直接將多個頁面合二為一,可能會出現變數名重複的現象,比如:

在主體頁面中定義一個i :

<%@include file="common/header.jsp"%>
<h1>網頁主體</h1>
<% int i = 10; %>
<%@include file="common/footer.jsp"%>
<hr>

在header.jsp中也定義一個i :

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<h1>我是頭部</h1>
<% int i = 2; %>

此時就會報錯,提示 變數 i 以在作用域中存在,以及 i 屬性值冗餘

taglib指令

用於指定頁面中使用的標籤庫及自定義標籤的字首
<%@ taglib prefix="c" uri=""%>
其中,uri用於指定標記庫存放分位置,prefix用於指定標記庫中所有動作元素名中使用的字首。

九大內建物件

按照內建物件的功能來劃分,可以分為以下四類:

輸出輸入物件

request物件(存資料)

response物件

out物件(輸出)

通訊控制物件

pageContext物件(存資料)

session物件(存資料)

application物件(存資料)

Servlet物件

page物件(幾乎不用)

config物件

錯誤處理物件

exception物件(異常,跟java一樣)

在內建物件中存東西

<body>
<%--內建物件--%>
<%

    pageContext.setAttribute("name1","阿飛1");//儲存的資料只在一個頁面中有效
    request.setAttribute("name2","阿飛2");//儲存的資料只在一次請求中有效,請求轉發時也會攜帶這個資料
    session.setAttribute("name3","阿飛3");//儲存的資料在一次會話中都有效,資料存在週期為從開啟瀏覽器到關閉瀏覽器
    application.setAttribute("name4","阿飛4");//儲存的資料在伺服器中有效,資料存在週期為從開啟伺服器到關閉伺服器
%>
<%--取出我們儲存的值--%>
<%--不能在jsp指令碼片段中使用jsp的註釋方式,因為這些程式碼會原封不動的生成到_jsp.java中,所以要使用java的註釋方式,以保證java語法的正確性--%>
<%
    //從pageContext取出儲存的值,通過尋找的方法,從底層到高層(作用域)來一層層的尋找 page——>request——>session——>application
    //JVM存在一個“雙親委派機制”
    String name1 = (String) pageContext.findAttribute("name1");
    String name2 = (String) pageContext.findAttribute("name2");
    String name3 = (String) pageContext.findAttribute("name3");
    String name4 = (String) pageContext.findAttribute("name4");
    String name5 = (String) pageContext.findAttribute("name5");//name5不存在
%>
<%--使用EL表示式輸出 ${}--%>
<h1>取出的值為:</h1>
<h3>${name1}</h3>
<h3>${name2}</h3>
<h3>${name3}</h3>
<h3>${name4}</h3>
</body>

JSP標籤,JSTL標籤,EL表示式

需要的依賴:

<!--jstl表示式依賴-->
<dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl-api</artifactId>
    <version>1.2</version>
</dependency>
<!--standard標籤庫依賴-->
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>

EL表示式(Expression Language):${}

  • 獲取資料
  • 執行運算
  • 獲取web開發的常用物件

JSP標籤:

<body>
<h1>1</h1>
<%--
相當於http://localhost:8080/javawebjsp/jsptag.jsp?name=afei&age=1000
--%>
<jsp:forward page="/jsptag02.jsp">
    <jsp:param name="name" value="afei"/>
    <jsp:param name="age" value="1000"/>
</jsp:forward>
</body>
<body>
<h1>2</h1>
<%--取出引數--%>
名字:<%=request.getParameter("name")%>
年齡:<%=request.getParameter("age")%>

</body>

JSTL標籤:

JSTL標籤庫的使用就是為了彌補HTML標籤的不足;它自定義了許多的標籤可以供我們使用,標籤的功能和java程式碼一樣。

需在jsp檔案中引入JSTL對應的標籤庫(taglib),才可以使用對應的JSTL標籤

如果引入標籤後依然報錯(JSTL解析錯誤),則還需要將JSTL的jar包複製到tomcat的lib目錄下

  • 核心標籤

    核心標籤的標籤庫:

    <%@ taglib prefix="c" url="http://java.sun.com/jsp/jstl/core" %>
    

    該標籤庫是c開頭的額,代表core,核心的意思

    c:if

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title> </title>
    </head>
    <body>
    <h4>if測試</h4>
    <hr>
    <form action="coreif.jsp" method="get">
        <%--EL表示式獲取表單中的資料
        格式為:${param.引數名}
        --%>
        <input type="text" name="username" value="${param.username}">
            <input type="submit" value="登陸">
    </form>
    <%--判斷如果提交的使用者名稱是管理員,則登陸成功--%>
    <c:if test="${param.username=='admin'}" var="isAdmin">
        <c:out value="管理員登陸"/>
    </c:if>
    <c:out value="${isAdmin}"/>
    </body>
    </html>
    

    c:set and c:when

    <body>
    <%--定義一個變數score,值為85--%>
    <c:set var="score" value="85"/>
    <%--判斷--%>
    <c:choose>
        <c:when test="${score>=90}">
            你的成績為優
        </c:when>
        <c:when test="${score>=75&&score<90}">
            你的成績為良
        </c:when>
        <c:when test="${score>=60&&score<75}">
            你的成績為及格
        </c:when>
        <c:when test="${score<60}">
            你的成績為不及格
        </c:when>
    </c:choose>
    </body>
    

    c:forEach

    <body>
    <%
        ArrayList<String> people = new ArrayList<>();
        people.add(0,"張三");
        people.add(1,"李四");
        people.add(2,"王五");
        people.add(3,"趙六");
        people.add(4,"孫七");
        people.add(5,"姬八");
        request.setAttribute("list",people);
    %>
    <%--
    var:每一次遍歷出來的變數
    items:要遍歷的物件
    --%>
    <c:forEach var="people" items="${list}">
        <c:out value="${people}"/><br>
    </c:forEach>
    <hr>
    <%--
    可以設定begin,end,step
    begin:設定開始的位置
    end:設定結束的位置
    step:遍歷的間隔,相當於i+?
    --%>
    <c:forEach var="people" items="${list}" begin="1" end="4" step="2"><%--輸出李四和趙六,對應的下標是1和3--%>
        <c:out value="${people}"/><br>
    </c:forEach>
    
    </body>
    
  • 格式化標籤

  • SQL標籤

  • XML標籤