什麼是JSP?html
JSP全名爲Java Server Pages,java服務器頁面。JSP是一種基於文本的程序,其特色就是HTMLjava
和Java代碼共同存在!web
爲何須要JSP?數據庫
JSP是爲了簡化Servlet的工做出現的替代品,Servlet輸出HTML很是困難,JSP就是替代Servlet輸出HTML的express
JSP還有必要學嗎?apache
在MVC中,JSP屬於展現層,可是JSP卻又能夠寫必定的業務,甚至跑去作數據層的事情,這樣開發中就會變得無比混亂,也增長了開發的困難程度,因此將展現層與業務層分開就成爲了主流,也就是咱們說的先後端分離,可是事無絕對,確實一些比較老的項目仍然在跑jsp,無論你會不會寫,你總得碰到能看懂吧,若是已經接近找工做,確實仍是以比較流行的技術學習比較好,可是若做爲學生,時間仍是比較富裕的,不少本科也必然都會講,學習一下也是挺好的,何況JSP與Servlet也是息息相關的,我認爲,學它就是爲了知道爲何之後會用別的技術代替它(狗頭保命),廢話有點多了,仍是有一點須要的朋友能夠簡單看一看,但願給你能有一點幫助後端
Tomcat訪問任何的資源都是在訪問Servlet!,固然了,JSP也不例外!JSP自己就是一種Servlet。爲何說JSP自己就是一種Servlet呢?設計模式
其實JSP在第一次被訪問的時候會被編譯爲HttpJspPage類(該類是HttpServlet的一個子類)數組
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>簡單使用JSP</title> </head> <body> <% String s = "HelloWorld"; out.println(s); %>
編譯過程是這樣子的:瀏覽器
瀏覽器第一次請求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 = "HelloWorld"; out.println(s);
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() { }
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
做用:用於配置JSP頁面,導入資源文件
格式: <%@ 指令名稱 屬性名1=屬性值1 屬性名2=屬性值2 ... %>
contentType:至關於response.setContentType()
設置當前jsp頁面的編碼(只能是高級的IDE才能生效,若是使用低級工具,則須要設置pageEncoding屬性設置當前頁面的字符集)
pageEncoding="characterSet | ISO-8859-1"
import:導包
import="{package.class | package.*}, ..."
errorPage:當前頁面發生異常後,會自動跳轉到指定的錯誤頁面
//主頁面 <%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %> //錯誤後轉到的頁面 <%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %> 咱們發現地址欄是沒有變化的,因此屬因而服務器跳轉。以上的作法是單個頁面設置的,若是我會有不少錯誤(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>
isErrorPage:標識當前也是是不是錯誤頁面
JSP行爲(JSP Actions)是一組JSP內置的標籤,只書寫少許的標記代碼就可以使用JSP提供豐富的功能,JSP行爲是對經常使用的JSP功能的抽象和封裝。
JSP內置的標籤稱之爲JSP行爲,是爲了可以和JSTL標籤區分開來。(叫作JSP標籤也行)
上面已經說起到了,include指令是靜態包含,include行爲是動態包含。其實include行爲就是封裝了request.getRequestDispatcher(String url).include(request,response)
include行爲語法是這樣的:
<jsp:include page=""/> 靜態包含:<%@ include file="被包含頁面"%> 動態包含:<jsp:include page="被包含頁面" flush="true">
<%@ 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>
jsp行爲包含文件就是先編譯被包含的頁面,再將頁面的結果寫入到包含的頁面中(1.jsp)
固然了,如今有靜態包含和動態包含,使用哪個更好呢?答案是:動態包含。
動態包含能夠向被包含的頁面傳遞參數(用處不大),而且是分別處理包含頁面的(將被包含頁面編譯後得出的結果再寫進包含頁面)
【若是有相同名稱的參數,使用靜態包含就會報錯!】!
當使用<jsp:include>和<jsp:forward>
行爲引入或將請求轉發給其它資源時,可使用<jsp:param>
行爲向這個資源傳遞參數
在Servlet中咱們使用request.getRequestDispatcher(String url).forward(request,response)進行跳轉。其實forward行爲就是對其封裝!
咱們來看一下forward的語法
<jsp:forward page=""/>
<%@ 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值爲aaa
<jsp:forward page="head.jsp"> <jsp:param name="username" value="aaa"/> </jsp:forward>
<% String ss = request.getParameter("username"); %> 獲取到的參數是: <%=ss%>
directive的中文意思就是指令。該行爲就是替代指令<%@%>
的語法的
· <jsp:directive.include file=""/> 至關於<%@include file="" %> · jsp:directive.page/ 至關於<%@page %> · jsp:directive.taglib/ 至關於<%@taglib %>
使用該指令可讓JSP頁面更加美觀!
使用scriptlet行爲<jsp:scriptlet>
替代<%%>是一樣一個道理
JSP還提供了操做javaBean對象的行爲,暫時記住JSP提供了javaBean行爲來操做簡單類便可!後面詳細解釋:
<jsp:useBean id=""/> <jsp:setProperty name="" property=""/> <jsp:getProperty name="" property=""/>
JSP引擎在調用JSP對應的jspServlet時,會傳遞或建立9個與web開發相關的對象供jspServlet使用。JSP技術的設計者爲便於開發人員在編寫JSP頁面時得到這些web對象的引用,特地定義了9個相應的變量,開發人員在JSP頁面中經過這些變量就能夠快速得到這9大對象的引用
變量名 | 真實類型 | 做用 |
---|---|---|
pageContext | PageContext | 當前頁面共享數據,還能夠獲取其餘八個內置對象 |
request | HttpServletRequest | 一次請求訪問的多個資源(轉發) |
session | HttpSession | 一次會話的多個請求間 |
application | ServletContext | 全部用戶間共享數據 |
response | HttpServletResponse | 響應對象 |
page | Object | 當前頁面(Servlet)的對象 this |
out | JspWriter | 輸出對象,數據輸出到頁面上 |
config | ServletConfig | Servlet的配置對象 |
exception | Throwable | 內置對象exception是java.lang.Exception類的對象 |
到目前爲止,咱們已經學了4種屬性範圍了。
page【只在一個頁面中保存屬性,跳轉頁面無效】
requet【只在一次請求中保存屬性,服務器跳轉有效,瀏覽器跳轉無效】
session【在一個會話範圍中保存屬性,不管何種跳轉均有效,關閉瀏覽器後無效】
application【在整個服務器中保存,全部用戶均可以使用】
4個內置對象都支持如下的方法:
avaBean就是一個普通的java類,也稱之爲簡單java對象--POJO(Plain Ordinary Java Object),是Java程序設計中一種設計模式,是一種基於 Java 平臺的軟件組件思想
JavaBean遵循着特定的寫法,一般有如下的規則:
有無參的構造函數
成員屬性私有化
封裝的屬性若是須要被外所操做,必須編寫public類型的setter、getter方法
上面的文字看起來好像很高大上,javaBean其實很是簡單,常見的學生類,書籍類就是按照特定寫法、規則編寫的一個JavaBean對象
使用javaBean的好處:封裝,重用,可讀!
JaveBean你能夠理解爲一輛貨車,在你的java端和web頁面進行數據傳遞的載體,你固然能夠每一個變量單獨傳遞,或者使用集合傳遞,可是javabean可使你的數據更有可讀性,方便開發時明確變量的意義,也使其餘閱讀你代碼的人能直接你的意圖
若是bean類與數據庫聯合使用,一張表使用bean類,可使你的代碼更加簡潔高效,易於理解,如今大多數框架都會使用這種機制。
JSP技術提供了三個關於JavaBean組件的動做元素,即JSP行爲(標籤),它們分別爲:
jsp:useBean【在JSP頁面中查找javaBean對象或者實例化javaBean對象】 jsp:setProperty【設置javaBean的屬性】 jsp:getProperty【獲取javaBean的屬性】
※ JSP:useBean
<jsp:useBean>
標籤用於在指定的域範圍內查找指定名稱的JavaBean對象:
存在則直接返回該JavaBean對象的引用。
不存在則實例化一個新的JavaBean對象並將它以指定的名稱存儲到指定的域範圍中。
語法:
jsp:useBean id="實例化對象的名稱" class="類的全名" scope="保存範圍"/>
果JSP不支持<jsp:useBean>
這個行爲,咱們要使用Person類是這樣使用的
<%--這裏須要導入Person類--%> <%@ page import="domain.Person" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title></title> </head> <body> <% //new出對象 Person person = new Person(); person.setName("admin"); System.out.println(person.getName()); %> </body>
可是咱們使用<jsp:useBean>
就很是整潔,不用導包,不用new對象
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title></title> </head> <body> <jsp:useBean id="person" class="domain.Person" scope="page"/> <% person.setName("zhongfucheng"); System.out.println(person.getName()); %> </body> </html>
JavaBean中無參的構造函數改爲有參的,會出現異常,這是由於<jsp:useBean>
的內部原理是 new了一個無參的構造函數
※ JSP:setProperty
<jsp:setProerty name="對象名稱" property="屬性名" param="參數名" value="值">
四種模式
<jsp:setProperty name="對象名稱" property="*"/>自動匹配 <jsp:setProperty name="對象名稱" property="屬性名稱"/>指定屬性 <jsp:setProperty name="對象名稱" property="屬性名稱" param="參數名稱"/>指定參 數【不多用】 <jsp:setProperty name="對象名稱" property="屬性名稱" value="內容"/>指定內容【很 少用】
當咱們沒有學習到<jsp:setProperty>
時,咱們獲取表單的信息,而後導入到javaBean對象中是這樣的一種狀況:
<jsp:useBean id="person" class="domain.Person" scope="page"/> <% int age = Integer.parseInt(request.getParameter("age")); person.setAge(age); System.out.println(person.getAge()); %>
而咱們使用<jsp:setProperty>
後,代碼更少,功能更強大
<jsp:useBean id="person" class="domain.Person" scope="page"/> <%--指定屬性名稱爲age--%> <jsp:setProperty name="person" property="age"/> <% System.out.println(person.getAge()); %>
代碼少很直觀的能夠看出來,可是強大在什麼地方呢?
表單提交過來的數據都是字符串,在咱們沒有用<jsp:setProperty>
前,咱們存儲設置int類型或其餘非字符串類型的數據是須要強轉的!可是<jsp:setProperty>
不須要咱們強轉,它內部自動幫咱們轉換了!
下面再經過自動匹配來感覺它的強大
<jsp:useBean id="person" class="domain.Person" scope="page"/> <%--property的值設置爲*就表明自動匹配--%> <jsp:setProperty name="person" property="*"/> <% System.out.println(person.getAge()); System.out.println(person.getName()); %>
爲何Property的值能夠將表單傳遞過來的數據封裝到JavaBean對象中?
JavaBean屬性名要和表單的name的名稱一致
是經過反射來作的,調用了內省的方法!
※ JSP:getProperty
<jsp:getProperty name="對象名" property="屬性名"/>
<%--使用<jsp:getProperty>輸出--%> <jsp:getProperty name="person" property="username"/> <jsp:getProperty name="person" property="age"/>
EL:Expression Language 表達式語言
它的做用就是替換和簡化jsp頁面中java代碼的編寫
EL表達式支持簡單的運算符:加減乘除取摸,邏輯運算符。empty運算符(判斷是否爲null),三目運算符
empty運算符能夠判斷對象是否爲null,用做於流程控制!
三目運算符簡化了if和else語句,簡化代碼書寫
<% List<Person> list = null; %> ${list==null?"list集合爲空":"list集合不爲空"}
EL表達式主要是來對內容的顯示,爲了顯示的方便,EL表達式提供了11個內置對象
pageContext 對應於JSP頁面中的pageContext對象(注意:取的是pageContext對象) pageScope 表明page域中用於保存屬性的Map對象 requestScope 表明request域中用於保存屬性的Map對象 sessionScope 表明session域中用於保存屬性的Map對象 applicationScope 表明application域中用於保存屬性的Map對象 param 表示一個保存了全部請求參數的Map對象 paramValues 表示一個保存了全部請求參數的Map對象,它對於某個請求參數,返回的是一個string[] header 表示一個保存了全部http請求頭字段的Map對象 headerValues 同上,返回string[]數組。 cookie 表示一個保存了全部cookie的Map對象 initParam 表示一個保存了全部web應用初始化參數的map對象
<%--模擬數據回顯場景--%> <% User user = new User(); user.setGender("male"); //數據回顯 request.setAttribute("user",user); %> <input type="radio" name="gender" value="male" ${user.gender=='male'?'checked':'' }>男 <input type="radio" name="gender" value="female" ${user.gender=='female'?'checked':'' }>女
EL自定義函數用於擴展EL表達式的功能,可讓EL表達式完成普通Java程序代碼所能完成的功能
開發HTML轉義的EL函數
咱們有時候想在JSP頁面中輸出JSP代碼,可是JSP引擎會自動把HTML代碼解析, 輸出給瀏覽器。此時咱們就要對HTML代碼轉義。
步驟:
編寫一個包含靜態方法的類(EL表達式只能調用靜態方法),該方法很經常使用,Tomcat都有此方法,可在webappsexamplesWEB-INFclassesutil中找到
public static String filter(String message) { if (message == null) return (null); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuilder result = new StringBuilder(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString());
在WEB/INF下建立tld(taglib description)文件,在tld文件中描述自定義函數
<?xml version="1.0" encoding="ISO-8859-1"?> <taglib xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd" version="2.1"> <tlib-version>1.0</tlib-version> <short-name>myshortname</short-name> <uri>/zhongfucheng</uri> <!--函數的描述--> <function> <!--函數的名字--> <name>filter</name> <!--函數位置--> <function-class>utils.HTMLFilter</function-class> <!--函數的方法聲明--> <function-signature>java.lang.String filter(java.lang.String)</function-signature> </function> </taglib>
在JSP頁面中導入和使用自定義函數,EL自定義的函數通常前綴爲"fn",uri是"/WEB-INF/tld文件名稱"
<%@ page language="java" contentType="text/html" pageEncoding="UTF-8" %> <%@taglib prefix="fn" uri="/WEB-INF/ideal.tld" %> <html> <head> <title></title> </head> <body> //完成了HTML轉義的功能 ${fn:filter("<a href='#'>點這裏</a>")} </body> </html>
在JSP頁面中指明使用標籤庫
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
JSTL全稱爲 JSP Standard Tag Library 即JSP標準標籤庫
JSTL做爲最基本的標籤庫,提供了一系列的JSP標籤,實現了基本的功能:集合的遍歷、數據的輸出、字符串的處理、數據的格式化等等!
EL表達式能夠很方便地引用一些JavaBean以及其屬性可是仍然不夠完美,它不能遍歷集合,作邏輯的控制。
Scriptlet的可讀性,維護性,重用性都十分差!JSTL與HTML代碼十分相似,遵循着XML標籤語法,使用JSTL讓JSP頁面顯得整潔,可讀性很是好,重用性很是高,能夠完成複雜的功能!
在JSP中不推薦使用scriptlet輸出,推薦使用JSP標籤
<%@ taglib %>
core標籤庫是JSTL的核心標籤庫,實現了最基本的功能:流程控制、迭代輸出等操做!
core標籤庫的前綴通常是c
經常使用的三個JSTL標籤
屬性:
test 必須屬性,接受boolean表達式
若是表達式爲true,則顯示if標籤體內容,若是爲false,則不顯示標籤體內容
<%--若是帶過來的名字是admin,那麼能夠登錄--%> <c:if test="${param.name=='admin'}"> 用戶名:<input type="text" name="username"><br> 密碼:<input type="password" name="password"><br> <input type="submit" value="登錄"> </c:if> <%--若是帶過來的名字是admin888,那麼就是註冊--%> <c:if test="${param.name=='admin888'}"> 用戶名:<input type="text" name="username"><br> 密碼:<input type="password" name="password"><br> <input type="submit" value="註冊"> </c:if>
它至關於java代碼的switch語句
使用choose標籤聲明,至關於switch聲明
使用when標籤作判斷,至關於case
使用otherwise標籤作其餘狀況的聲明,至關於default
<c:choose> <c:when test="${param.name=='admin'}"> 歡迎管理員 </c:when> <c:when test="${param.name=='user'}"> 歡迎用戶 </c:when> <c:otherwise> 識別不出你是誰 </c:otherwise> </c:choose>
forEach爲循環標籤,至關於Java中的while和for
以前咱們在使用EL表達式獲取到集合的數據,遍歷集合都是用scriptlet代碼循環,如今咱們學了forEach標籤就能夠捨棄scriptlet代碼
向Session中設置屬性,屬性的類型是List集合
向Session中設置屬性,屬性的類型是List集合
遍歷session屬性中的List集合,items:即將要迭代的集合。var:當前迭代到的元素
<% List list = new ArrayList<>(); list.add("admin"); list.add("zhangsan"); list.add("lisi"); session.setAttribute("list", list); %> ===================================================== <c:forEach var="list" items="${list}" > ${list}<br> </c:forEach>
Map對象有稍微地不同保存的不是每一個迭代的對象,而是Map.Entry
<% Map map = new HashMap(); map.put("1", "tom"); map.put("2", "jack"); map.put("3", "jack」); session.setAttribute("map",map); %> <c:forEach var="me" items="${map}" > ${me.key} ${me.value}<br> </c:forEach>
特別說明:本篇中 第二 第三篇部份內容轉載來自 java3y 所寫jsp第四篇內容,在做者基礎上摘出片斷,附上連接:
https://juejin.im/post/5a7919...
若是內容中有什麼不足,或者錯誤的地方,歡迎你們給我留言提出意見, 蟹蟹你們 !^_^
若是能幫到你的話,那就來關注我吧!(系列文章均會在公衆號第一時間更新)
在這裏的咱們素不相識,卻都在爲了本身的夢而努力 ❤一個堅持推送原創Java技術的公衆號:理想二旬不止