什麼是JSP
JSP全名為Java Server Pages,java伺服器頁面。JSP是一種基於文字的程式,其特點就是HTML和Java程式碼共同存在!
為什麼需要JSP
JSP是為了簡化Servlet的工作出現的替代品,Servlet輸出HTML非常困難,JSP就是替代Servlet輸出HTML的。
簡單使用一下JSP
- 在idea下生成一個JSP,我們來看一下JSP長什麼樣子
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>簡單使用JSP</title>
</head>
<body>
</body>
</html>
複製程式碼
- 看起來就像一個HTML頁面,前面也說了:JSP的特點就是HTML和Java程式碼共同存在
- 我們向瀏覽器輸出一句HelloWorld,至於<%%>這個東西,我先不解釋!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>簡單使用JSP</title>
</head>
<body>
<%
String s = "HelloWorld";
out.println(s);
%>
</body>
</html>
複製程式碼
JSP的工作原理
- 在Tomcat部落格中我提到過:Tomcat訪問任何的資源都是在訪問Servlet!,當然了,JSP也不例外!JSP本身就是一種Servlet。為什麼我說JSP本身就是一種Servlet呢?其實JSP在第一次被訪問的時候會被編譯為HttpJspPage類(該類是HttpServlet的一個子類)
- 剛才我簡單使用了一下JSP,它被編譯成了這麼一個Servlet:
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import java.util.Date;
public final class _1_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
private static java.util.List<String> _jspx_dependants;
private javax.el.ExpressionFactory _el_expressionfactory;
private org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.List<String> getDependants() {
return _jspx_dependants;
}
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
public void _jspDestroy() {
}
public void _jspService(final HttpServletRequest request, final HttpServletResponse response)
throws java.io.IOException, ServletException {
final PageContext pageContext;
HttpSession session = null;
final ServletContext application;
final ServletConfig config;
JspWriter out = null;
final Object page = this;
JspWriter _jspx_out = null;
PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>簡單使用JSP</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
String s = "HelloWorda";
out.println(s);
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try { out.clearBuffer(); } catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
複製程式碼
- 編譯過程是這樣子的:瀏覽器第一次請求1.jsp時,Tomcat會將1.jsp轉化成1_jsp.java這麼一個類,並將該檔案編譯成class檔案。編譯完畢後再執行class檔案來響應瀏覽器的請求。
- 以後訪問1.jsp就不再重新編譯jsp檔案了,直接呼叫class檔案來響應瀏覽器。當然了,如果Tomcat檢測到JSP頁面改動了的話,會重新編譯的。
- 既然JSP是一個Servlet,那JSP頁面中的HTML排版標籤是怎麼樣被髮送到瀏覽器的?我們來看下上面1_jsp.java的原始碼就知道了。原來就是用write()出去的罷了。說到底,JSP就是封裝了Servlet的java程式罷了。
out.write("\r\n");
out.write("\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write(" <title>簡單使用JSP</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
複製程式碼
- 有人可能也會問:JSP頁面的程式碼伺服器是怎麼執行的?再看回1_jsp.java檔案,java程式碼就直接在類中的service()中。
String s = "HelloWorda";
out.println(s);
複製程式碼
- **JSP比Servlet更方便更簡單的一個重要原因就是:內建了9個物件!**內建物件有:out、session、response、request、config、page、application、pageContext、exception,這幾個內建物件不在這裡講。現在先知道一下即可!
JSP生命週期
JSP也是Servlet,執行時只有一個例項,JSP初始化和銷燬時也會呼叫Servlet的init()和destroy()方法。另外,JSP還有自己初始化和銷燬的方法
public void _jspInit() {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
public void _jspDestroy() {
}
複製程式碼
JSP的語法
JSP程式碼可以分為兩部分:
- 模板資料:就是HTML程式碼
- 元素:JSP頁面中的java程式碼、JSP指令、JSP標籤
JSP指令碼
-
JSP的指令碼就是JSP頁面中的java程式碼,也叫做scriptlet。JSP的指令碼必須使用<%%>括起來,不然會被當成是模板資料的!
-
JSP指令碼有三種方式:
- <%%>【定義區域性變數,編寫語句】
- <%!%>【定義類或方法,但是沒人這樣用!】
- <%=%>(也稱之為表示式輸出)【輸出各種型別的變數,int、double、String、Object等】
-
如果過多地使用<%%>會導致程式碼混亂,JSP還提供了一種scriptlet標籤,使用此標籤和<%%>有相同的功能,只不過它更美觀了一些
<jsp:scriptlet>
String s = "HelloWorld";
out.println(s);
</jsp:scriptlet>
複製程式碼
JSP註釋##
<%--這是JSP註釋--%>
<%--%>
//這是java的當行註釋
//
/*這是java的多行註釋*/
/**/
複製程式碼
JSP指令
JSP指令用來宣告JSP頁面的相關屬性,例如編碼方式、文件型別等等
JSP指令的語法:
<%@指令 屬性名="值" %>
複製程式碼
page指令
- 我在idea生成的JSP頁面就有page指令了。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
複製程式碼
-
page指令常見屬性:
-
language="java"
-
extends="package.class"
-
import="{package.class | package.*}, ..."
-
session="true | false"
-
buffer="none | 8kb | sizekb"
-
autoFlush="true | false"
-
isThreadSafe="true | false"
-
info="text"
-
errorPage="relative_url"
-
isErrorPage="true | false"
-
contentType="mimeType ;charset=characterSet " | "text/html ; charset=ISO-8859-1"
-
pageEncoding="characterSet | ISO-8859-1"
-
isELIgnored="true | false"
-
一般地,在eclipse或idea這些高階開發工具上開發,我們只需要在page指令中指定contentType="text/html;charset=UTF-8",就不會出現中文亂碼問題!
-
當然了contentType 不僅僅可以指定以text/html的方式顯示,還可以使用其他的形式顯示出來。在conf/web.xml檔案中可以查詢出來
- 比如,我以doc形式顯示jsp的資料
<%@ page contentType="application/msword;charset=UTF-8" language="java" %>
<html>
<head>
<title>簡單使用JSP</title>
</head>
<body>
1111
</body>
</html>
複製程式碼
- 效果是這樣子的:
- 我們上網的時候,如果我們操作不當,或者伺服器出錯了,頁面都是會出現友好提示的!這個也能通過page指令來實現跳轉到友好提示頁面上!
- page指令errorPage=和isErrorPage這兩個屬性,下面我們來看一下怎麼使用!
- 1.jsp出現了錯誤,通過page指令的errorPage屬性跳轉到error.jsp頁面上
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>
<html>
<head>
<title>該頁面出錯了!</title>
</head>
<body>
<%--模擬頁面出錯了!!!--%>
<%
int result = 2 / 0;
%>
你好呀
</body>
</html>
複製程式碼
- error.jsp頁面要通過page指令的isErrorPage屬性設定頁面就是錯誤頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
<title>友好提示頁面</title>
</head>
<body>
伺服器正忙著呢!
</body>
</html>
複製程式碼
- 下面是效果:
- 當然了,細心的朋友可以發現位址列是沒有變化的,所以屬於是伺服器跳轉。以上的做法是單個頁面設定的,如果我會有很多錯誤(JSP多的情況下,錯誤就會多),單個設定太麻煩了!
- 我們可以在web.xml檔案中全域性設定錯誤頁,只要發生了404錯誤或者空指標異常的錯誤都會跳轉到error.jsp頁面上
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/error.jsp</location>
</error-page>
複製程式碼
- 隨便輸個資源進行,會發生髮404錯誤的,跳轉到錯誤頁面。下面是效果:
include指令
-
在講解request物件的時候,我們曾經使用過request.getRequestDispatcher(String url).include(request,response)來對頁頭和頁尾面進行包含
-
inclue指令也是做這樣的事情,我們來試驗一下吧!
-
這是頁頭
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁頭</title>
</head>
<body>
我是頁頭
<br>
<br>
<br>
</body>
</html>
複製程式碼
- 這是頁尾
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁尾</title>
</head>
<body>
我是頁尾
</body>
</html>
複製程式碼
- 在1.jsp中把頁頭和頁尾包含進來
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>包含頁頭和頁尾進來</title>
</head>
<body>
<%@include file="head.jsp" %>
<%@include file="foot.jsp" %>
</body>
</html>
複製程式碼
- 訪問1.jsp
- include指令是靜態包含。靜態包含的意思就是:把檔案的程式碼內容都包含進來,再編譯!,看一下jsp的原始碼就知道了!
- jsp還提供另一種包含檔案的方式:JSP行為---動態包含。jsp行為在下面會講到!
taglib指令
- JSP支援標籤技術,要使用標籤技術就先得宣告標籤庫和標籤字首。taglib指令就是用來指明JSP頁面內使用標籤庫技術。
- 這裡就不詳細說明了,等到學習JSP標籤的時候再使用吧!現在記住有這個指令即可。
JSP行為
JSP行為(JSP Actions)是一組JSP內建的標籤,只書寫少量的標記程式碼就能夠使用JSP提供豐富的功能,JSP行為是對常用的JSP功能的抽象和封裝。
為什麼我不把它直接稱為JSP標籤呢?我把這些JSP內建的標籤稱之為JSP行為,能夠和JSTL標籤區分開來。當然了,你也可以把它稱之為JSP標籤,你不要搞混就行了。我個人喜歡把這些JSP內建標籤稱之為JSP行為。
include行為
- 上面已經提及到了,include指令是靜態包含,include行為是動態包含。其實include行為就是封裝了request.getRequestDispatcher(String url).include(request,response)
- include行為語法是這個樣子的
<jsp:include page=""/>
複製程式碼
- 我們先來使用一下把,在1.jsp頁面中也將頁頭和頁尾包含進來。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>包含頁頭和頁尾進來</title>
</head>
<body>
<jsp:include page="head.jsp"/>
<jsp:include page="foot.jsp"/>
</body>
</html>
複製程式碼
- 訪問1.jsp頁面看一下效果:
- 使用jsp行為來包含檔案,jsp原始檔是這樣子的:
-
jsp行為包含檔案就是先編譯被包含的頁面,再將頁面的結果寫入到包含的頁面中(1.jsp)
-
當然了,現在有靜態包含和動態包含,使用哪一個更好呢?答案是:動態包含。
-
動態包含可以向被包含的頁面傳遞引數(用處不大),並且是分別處理包含頁面的(將被包含頁面編譯後得出的結果再寫進包含頁面)【如果有相同名稱的引數,使用靜態包含就會報錯!】!
-
模擬一下場景吧,現在我的頭頁面有個名為s的字串變數
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁頭</title>
</head>
<body>
<%
String s = "zhongfucheng";
%>
我是頁頭呀
<br>
<br>
<br>
</body>
</html>
複製程式碼
- 我的頁尾也有個名為s的字串變數
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>頁尾</title>
</head>
<body>
<%
String s = "zhongfucheng";
%>
我是頁尾呀
</body>
</html>
複製程式碼
- 現在我使用靜態包含看看會發生什麼,出現異常了。
- 出現異常的原因很簡單,就是同一個檔案中有兩個相同的變數s
- 使用動態包含就可以避免這種情況
param行為
- 當使用jsp:include和jsp:forward行為引入或將請求轉發給其它資源時,可以使用jsp:param行為向這個資源傳遞引數。
forward行為
- 在講解request物件的時候,我們使用request.getRequestDispatcher(String url).forward(request,response)進行跳轉。其實forward行為就是對其封裝!
- 我們來看一下forward的語法:
<jsp:forward page=""/>
複製程式碼
- 好的,我們來使用一下吧。訪問1.jsp頁面就跳轉到head.jsp頁面中
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>訪問1.jsp就跳轉到head.jsp</title>
</head>
<body>
<jsp:forward page="head.jsp"/>
</body>
</html>
複製程式碼
- 看一下效果
- 如果我要傳遞引數,就要在forward行為巢狀param行為
- 在跳轉到head.jsp時傳入引數username值為zhongfucheng
<jsp:forward page="head.jsp">
<jsp:param name="username" value="zhongfucheng"/>
</jsp:forward>
複製程式碼
- 在head.jsp頁面中獲取到傳遞過來的引數
<%
String ss = request.getParameter("username");
%>
獲取到的引數是:
<%=ss%>
複製程式碼
- 效果如下圖所示
directive行為
-
directive的中文意思就是指令。該行為就是替代指令<%@%>的語法的
- <jsp:directive.include file=""/> 相當於<%@include file="" %>
- jsp:directive.page/ 相當於<%@page %>
- jsp:directive.taglib/ 相當於<%@taglib %>
-
我們來試一下能不能用的
<jsp:directive.include file="head.jsp"></jsp:directive.include>
<jsp:directive.include file="foot.jsp"></jsp:directive.include>
複製程式碼
- 看下效果,正常可以包含頁面:
- 使用該指令可以讓JSP頁面更加美觀!
- 使用scriptlet行為
<jsp:scriptlet>
替代<%%>是同樣一個道理
javaBean行為
- JSP還提供了操作javaBean物件的行為,在這裡就不詳細說明了,後面會講到的!現在記住JSP提供了javaBean行為來操作簡單類即可!
<jsp:useBean id=""/>
<jsp:setProperty name="" property=""/>
<jsp:getProperty name="" property=""/>
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,可以關注微信公眾號:Java3y