javascript
重学JavaWeb —— JSP,简单全面一发入魂
文章目錄
- JSP
- 特點
- 由來
- 本質(zhì)
- 使用
- JSP指令
- page
- include
- taglib
- JSP腳本
- JSP內(nèi)置對象
- JSP作用域
- EL表達(dá)式
- EL內(nèi)置對象
- EL取值方式
- JSP動作元素
- JSTL標(biāo)簽庫
- 配置
- 使用
JSP
Java Server Page
特點
- 是一種動態(tài)資源(不要將JSP等同于HTML,jsp實際并不是靜態(tài)的頁面文件)
- 運行在服務(wù)端
- 本質(zhì)是Servlet
由來
為什么有JSP?
在早期的JavaWeb開發(fā)時,程序員需要在Servlet中手動拼接HTML標(biāo)簽和動態(tài)的數(shù)據(jù),如下
@WebServlet(urlPatterns = "/page") public class PageServlet extends HttpServlet {protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setCharacterEncoding("utf-8");PrintWriter writer = response.getWriter();String data = "你好";writer.write("<html>\n");writer.write(" <head>\n");writer.write(" <body>\n");writer.write(" <h1>\n");writer.write(data);writer.write(" </h1>\n");writer.write(" </body>\n");writer.write(" </head>\n");writer.write("</html>\n");}protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);} }可謂非常反人類了,這也導(dǎo)致了當(dāng)時很多java陣營的web開發(fā),投入了php,asp等動態(tài)語言的懷抱
本質(zhì)
于是,Java官方推出了JSP這一技術(shù),聲稱可以直接在HTML頁面中書寫Java代碼,這就避免了原先的需要手動拼接HTML標(biāo)簽的麻煩。比如,可以有如下的JSP文件
<!-- demo.jsp --> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body><%String user = request.getParameter("user");String password = request.getParameter("password");// 執(zhí)行數(shù)據(jù)庫查詢// 得到賬戶余額int remainMoney = 100;%> <h1>你好, <%= user%>, 你賬戶上還剩 <%= remainMoney%> 元</h1> </body> </html>當(dāng)訪問上面這個demo.jsp時,會由JSP引擎,針對該JSP文件,生成一個Servlet類,在Servlet類中完成處理,并返回響應(yīng)。用瀏覽器訪問,結(jié)果如下
此時,查看IDEA的tomcat工作目錄(位置是:C:\Users\用戶名\.IntelliJIdeaxxx\system\tomcat\項目名\work\),可以看到,針對demo.jsp,生成了一個java類demo_jsp
查看這個類
可以看到核心的代碼,還是進行了HTML標(biāo)簽的拼接,只不過這個拼接過程是程序自動完成的而已。
我們可以看到,這個類繼承了HttpJspBase
而HttpJspBase這個類,在tomcat的lib下的jasper.jar這個包下
可以看到這個HttpJspBase實現(xiàn)了HttpServlet,即它也是個Servlet。所以我們說,JSP的本質(zhì)就是Servlet。
當(dāng)我們在瀏覽器訪問http://localhost:8080/demo.jsp時,注意,實際展示的并不是demo.jsp這個頁面,而是根據(jù)demo.jsp這個urlPattern,匹配到了tomcat中默認(rèn)的一個Servlet。我們打開tomcat的conf目錄下的web.xml,可以看到有如下的配置
可以看到,對于以.jsp或.jspx結(jié)尾的url,會交給一個名為jsp的servlet處理,這個servlet是org.apache.jasper.servlet.JspServlet對象。這個對象,會解析jsp文件,并生成了對應(yīng)的Java類(Servlet),并調(diào)用這個Servlet完成對請求的處理。這就是JSP的本質(zhì)。
小結(jié):
JSP的本質(zhì)是:當(dāng)請求一個JSP文件時,由tomcat內(nèi)置的JSP引擎(JspServlet),解析該JSP文件,生成一個對應(yīng)的Servlet類,并執(zhí)行這個Servlet類,完成對請求的響應(yīng)。
使用
JSP頁面中,可同時編寫HTML標(biāo)簽,Java代碼,以及一些JSP的代碼。下面對JSP的使用進行基本介紹
JSP指令
又叫JSP編譯指令,采用<%@ code %>包裹,一般放在JSP頁面最前面,它的作用是,通知JSP引擎,告訴JSP引擎,在解析本JSP文件時,需要對何種屬性進行何種設(shè)置。
包含了3個指令,page,include,taglib
page
這個指令,主要用于在JSP轉(zhuǎn)換為servlet類時,進行一些屬性配置,支持對如下屬性進行配置
- contentType:等同于response.setContentType
- language:指定JSP頁面所使用的腳本語言(默認(rèn)是java,目前也只支持java,= =!汗)
- import:導(dǎo)入需要的java類
- pageEncoding:頁面的編碼格式
- session:用來控制請求jsp頁面時是否會自動創(chuàng)建session對象
- isErrorPage:標(biāo)識該jsp是否是錯誤頁面
- errorPage:當(dāng)前jsp執(zhí)行java代碼出現(xiàn)異常后,需要跳轉(zhuǎn)到的頁面
在IDEA里可以查看page支持的所有屬性
若遇到JSP頁面的中文亂碼,可以通過如下page指令進行編碼設(shè)置
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>include
用于在當(dāng)前JSP頁面中,導(dǎo)入另外的JSP頁面,使用方法如下
<!-- demo.jsp中 --> <%@ include file="index.jsp" %>注意,這是靜態(tài)導(dǎo)入。這也就是說,當(dāng)用戶請求主JSP頁面時,不會對導(dǎo)入的從JSP另外生成一個servlet,而是會將從JSP的內(nèi)容,合并到主JSP生成的servlet中。以上面的代碼為例,當(dāng)用戶請求demo.jsp時,tomcat只會為demo.jsp生成一個servlet,而index.jsp中的內(nèi)容,會并入到demo.jsp對應(yīng)的servlet中。這樣做,好處是,運行效率高;壞處是,若主jsp文件和從jsp文件中定義了相同名稱的變量,方法等,則會產(chǎn)生沖突,報錯,增大了維護jsp的成本。示例如下,現(xiàn)有一個my.jsp,內(nèi)容如下
<!-- my.jsp --> <%@page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> </head> <body>This is my.jsp <%@include file="static.jsp"%> </body> </html>其中static.jsp的內(nèi)容如下
<!-- static.jsp --> <%@page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> </head> <body> 我是靜態(tài)導(dǎo)入頁面 </body> </html>訪問my.jsp,能夠看到如下頁面
找到IDEA的tomcat的work目錄,能夠看到只生成了my.jsp對應(yīng)的servlet文件(這也就是說,不會對導(dǎo)入的static.jsp另外生成一個servlet)
my.jsp對應(yīng)的servlet代碼如下
既然有靜態(tài)導(dǎo)入,那么相對應(yīng)的,就有動態(tài)導(dǎo)入,動態(tài)導(dǎo)入是通過JSP動作標(biāo)簽<jsp:include>來進行的,如下所示
<jsp:include page="dynamic.jsp"/>動態(tài)導(dǎo)入,主JSP文件和從JSP文件,都會分別生成屬于自己的servlet文件。2個servlet一前一后,分別執(zhí)行,頁面在最終顯示的時候是合并的。若采用動態(tài)導(dǎo)入,則兩個JSP頁面完全獨立,若定義了相同名稱的變量,方法等,則不會發(fā)生沖突。動態(tài)導(dǎo)入的優(yōu)點是,2個JSP頁面沒有耦合,可維護性好,至于缺點,由于要分別生成2個servlet,自然性能要略差于靜態(tài)導(dǎo)入。
演示如下
有一個my.jsp文件,其內(nèi)容如下
<!-- my.jsp --> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> </head> <body> This is my.jsp <jsp:include page="dynamic.jsp"/> </body> </html>其中導(dǎo)入的dynamic.jsp的內(nèi)容如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> </head> <body> 我是動態(tài)導(dǎo)入頁面 </body> </html>請求my.jsp,效果如下
找到IDEA的tomcat的work目錄,可以看到生成了2個servlet
查看my.jsp對應(yīng)的servlet,內(nèi)容如下
動態(tài)導(dǎo)入和靜態(tài)導(dǎo)入對比
| 使用方法 | <jsp:include page=“dynamic.jsp”/> | <%@include file=“static.jsp”%> |
| 運行效率 | 略差 | 略優(yōu) |
| JSP頁面耦合度 | 耦合度低,JSP頁面之間相互獨立,可維護性好 | 耦合度高,可維護性差 |
| servlet個數(shù) | 生成2個servlet | 只生成1個servlet |
| 同名變量 | 2個jsp頁面中可以有同名變量,方法等 | 2個jsp頁面中不能有同名變量,方法等 |
taglib
用于引入自定義標(biāo)簽庫,如引入JSTL標(biāo)簽庫
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>隨后在JSP頁面中,即可以c為前綴,使用JSTL的核心標(biāo)簽庫,如
<c:set var="a" value="10"/> <c:if test="${a > 5}" var="result" scope="request"><h1>a = ${a} , JSTL is easy</h1> </c:if>JSP腳本
上面說到,JSP頁面中,也可以編寫Java代碼。
JSP中的Java代碼片段,稱為JSP腳本,目前JSP腳本支持的語言只有Java。
JSP中的Java代碼片段,需要用<% %>進行包裹,共分為3種
- <% code %>:普通Java代碼。
- <%= code %>:Java表達(dá)式
- <%! code %>:用于定義類的成員變量和成員方法等
用一個實際的示例來進行說明,假設(shè)有如下的jsp文件demo.jsp
<%@ page import="java.time.format.DateTimeFormatter" %> <%@ page import="java.time.LocalDateTime" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Title</title> </head> <body> <%!private static final DateTimeFormatter dtf;static {dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");}public static String now() {return dtf.format(LocalDateTime.now());} %><%String user = request.getParameter("user");String password = request.getParameter("password");// 執(zhí)行數(shù)據(jù)庫查詢// 得到賬戶余額int remainMoney = 100; %> <h1>你好, 當(dāng)前時間是: <%= now()%> , 你的賬戶名是 <%= user%>, 你賬戶上還剩 <%= remainMoney%> 元</h1> </body> </html>上面的JSP文件包含了3種類型的Java代碼片段。我們用瀏覽器訪問demo.jsp,結(jié)果如下
查看demo.jsp編譯生成的servlet代碼,如下(注意查看其中的注釋,注釋為手動添加)
/** Generated by the Jasper component of Apache Tomcat* Version: Apache Tomcat/8.5.47* Generated at: 2021-01-20 02:38:55 UTC* Note: The last modified time of this file was set to* the last modified time of the source file after* generation to assist with modification tracking.*/ package org.apache.jsp;import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import java.time.format.DateTimeFormatter; // 這里是 page 指令設(shè)置import屬性, 導(dǎo)入的java類 import java.time.LocalDateTime; // 這里是 page 指令設(shè)置import屬性, 導(dǎo)入的java類public final class demo_jsp extends org.apache.jasper.runtime.HttpJspBaseimplements org.apache.jasper.runtime.JspSourceDependent,org.apache.jasper.runtime.JspSourceImports {/** <!% code %> 中的Java代碼,會被添加到定義類的成員的地方, 也就是這里 **/private static final DateTimeFormatter dtf;static {dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");}public static String now() {return dtf.format(LocalDateTime.now());}/** <!% code %> 中的Java代碼,會被添加到定義類的成員的地方, 也就是這里 **/private static final javax.servlet.jsp.JspFactory _jspxFactory =javax.servlet.jsp.JspFactory.getDefaultFactory();private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;private static final java.util.Set<java.lang.String> _jspx_imports_packages;private static final java.util.Set<java.lang.String> _jspx_imports_classes;static {_jspx_imports_packages = new java.util.HashSet<>();_jspx_imports_packages.add("javax.servlet");_jspx_imports_packages.add("javax.servlet.http");_jspx_imports_packages.add("javax.servlet.jsp");_jspx_imports_classes = new java.util.HashSet<>();_jspx_imports_classes.add("java.time.format.DateTimeFormatter");_jspx_imports_classes.add("java.time.LocalDateTime");}private volatile javax.el.ExpressionFactory _el_expressionfactory;private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;public java.util.Map<java.lang.String,java.lang.Long> getDependants() {return _jspx_dependants;}public java.util.Set<java.lang.String> getPackageImports() {return _jspx_imports_packages;}public java.util.Set<java.lang.String> getClassImports() {return _jspx_imports_classes;}public javax.el.ExpressionFactory _jsp_getExpressionFactory() {if (_el_expressionfactory == null) {synchronized (this) {if (_el_expressionfactory == null) {_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();}}}return _el_expressionfactory;}public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {if (_jsp_instancemanager == null) {synchronized (this) {if (_jsp_instancemanager == null) {_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());}}}return _jsp_instancemanager;}public void _jspInit() {}public void _jspDestroy() {}public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {final java.lang.String _jspx_method = request.getMethod();if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");return;}final javax.servlet.jsp.PageContext pageContext;javax.servlet.http.HttpSession session = null;final javax.servlet.ServletContext application;final javax.servlet.ServletConfig config;javax.servlet.jsp.JspWriter out = null;final java.lang.Object page = this;javax.servlet.jsp.JspWriter _jspx_out = null;javax.servlet.jsp.PageContext _jspx_page_context = null;try {response.setContentType("text/html;charset=UTF-8"); // 這里就是 page 指令中設(shè)置的Content-Type屬性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("\n");out.write("\n");out.write("\n");out.write("<html>\n");out.write("<head>\n");out.write(" <title>Title</title>\n");out.write("</head>\n");out.write("<body>\n");out.write('\n');out.write('\n');/** 下面就是 <% code %> 中的 Java 代碼 **/String user = request.getParameter("user");String password = request.getParameter("password");// 執(zhí)行數(shù)據(jù)庫查詢// 得到賬戶余額int remainMoney = 100;/** 上面就是 <% code %> 中的 Java 代碼 **/out.write("\n");out.write("<h1>你好, 當(dāng)前時間是: ");out.print( now()); /** 這里就是 <%= code %> 中的內(nèi)容, 是個Java表達(dá)式,會以這種形式追加到HTML數(shù)據(jù)中 **/out.write(" , 你的賬戶名是 ");out.print( user); /** 這里就是 <%= code %> 中的內(nèi)容, 是個Java表達(dá)式,會以這種形式追加到HTML數(shù)據(jù)中 **/out.write(", 你賬戶上還剩 ");out.print( remainMoney); /** 這里就是 <%= code %> 中的內(nèi)容, 是個Java表達(dá)式,會以這種形式追加到HTML數(shù)據(jù)中 **/out.write(" 元</h1>\n");out.write("</body>\n");out.write("</html>");} catch (java.lang.Throwable t) {if (!(t instanceof javax.servlet.jsp.SkipPageException)){out = _jspx_out;if (out != null && out.getBufferSize() != 0)try {if (response.isCommitted()) {out.flush();} else {out.clearBuffer();}} catch (java.io.IOException e) {}if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);else throw new ServletException(t);}} finally {_jspxFactory.releasePageContext(_jspx_page_context);}} }對于需要通過Java代碼來控制是否需要展示的HTML標(biāo)簽,可以像下面這樣寫(可見非常不方便,要反復(fù)的使用<% %>)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <%String str = request.getParameter("score");int score = Integer.parseInt(str); %> <h3>你的成績是: <%= score%></h3> <%if (score > 90) { %> <h1>優(yōu)秀!</h1> <% } %> </body> </html>訪問:
JSP內(nèi)置對象
觀察上面JSP文件轉(zhuǎn)化成的servlet文件,我們會發(fā)現(xiàn)servlet文件中自動幫我們創(chuàng)建了一些對象。
下面截取一個自動生成的servlet文件中的_jspService方法(這個方法其實就相當(dāng)于Servlet中的service方法,具體原理可以查看tomcat的lib目錄中jasper.jar中的org.apache.jasper.runtime.HttpJspBase,所有JSP文件轉(zhuǎn)化成的servlet,都是繼承自這個類)
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)throws java.io.IOException, javax.servlet.ServletException {final java.lang.String _jspx_method = request.getMethod();if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");return;}final javax.servlet.jsp.PageContext pageContext;javax.servlet.http.HttpSession session = null;final javax.servlet.ServletContext application;final javax.servlet.ServletConfig config;javax.servlet.jsp.JspWriter out = null;final java.lang.Object page = this;javax.servlet.jsp.JspWriter _jspx_out = null;javax.servlet.jsp.PageContext _jspx_page_context = null;try {response.setContentType("text/html;charset=UTF-8"); // 這里就是 page 指令中設(shè)置的Content-Type屬性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;// 剩余代碼略...} }可以看到,在service方法中,為我們自動生成了不少對象,比如pageContext,session,application等,這也就使得,我們可以在JSP頁面中,直接使用這些對象,如下圖
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <%request.setAttribute("user", "Ezreal");pageContext.setAttribute("game", "League of Legends");session.setAttribute("ult", "精準(zhǔn)彈幕");response.addCookie(new Cookie("tips", "我是一塊小餅干")); %> </body> </html>這些自動生成的對象,稱為JSP內(nèi)置對象,共有9個,在JSP生成的servlet中,它們的變量名稱及對應(yīng)的類分別如下
- request:HttpServletRequest對象,封裝了請求的數(shù)據(jù)
- response:HttpServletResponse對象,封裝了響應(yīng)的數(shù)據(jù)
- session:HttpSession對象
- pageContext:PageContext對象,當(dāng)前JSP頁面上下文
- application:ServletContext對象,web應(yīng)用全局上下文
- out:JspWriter對象,用于將數(shù)據(jù)輸出到頁面
- config:ServletConfig對象,當(dāng)前servlet的配置
- page:相當(dāng)于當(dāng)前servlet的this指針
- exception:異常對象,當(dāng)當(dāng)前JSP頁面被標(biāo)記為錯誤頁面時(設(shè)置isErrorPage=true),才有該對象
可以自己嘗試使用page命令對JSP頁面進行配置,然后觀察生成的servlet類。比如,設(shè)置
<%@page session="false"%>可以觀察到生成的servlet類中,就不會自動創(chuàng)建HttpSession對象了
JSP作用域
在9大內(nèi)置對象中,有4個對象可以用來存儲數(shù)據(jù),這4個對象又稱為4大作用域?qū)ο?/strong>,它們分別是
- pageContext
- request
- session
- application
這些對象中都有setAttribute和getAttribute方法,可以往對象中設(shè)置數(shù)據(jù)
EL表達(dá)式可以很方便的從域?qū)ο笾蝎@取數(shù)據(jù)
EL表達(dá)式
Express Language ,它是一種表達(dá)式語言,其作用是為了方便JSP頁面從域?qū)ο笾蝎@取數(shù)據(jù)
下面分別展示了使用原始方式,和使用EL表達(dá)式方式來從域?qū)ο笾腥≈怠?梢?#xff0c;EL表達(dá)式更加的簡便
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <% request.setAttribute("location","廣州"); %> 原始方式:<br/> name: <%= request.getParameter("name")%> <!-- 取HTTP請求中的參數(shù) --> pwd: <%= request.getParameter("pwd")%> location: <%= request.getAttribute("location")%> <!-- 取request域?qū)ο笾械膌ocation屬性 --> <br/> EL表達(dá)式:<br/> name: ${param.name} <!-- 取HTTP請求中的參數(shù) --> pwd: ${param.pwd} location: ${location} <!-- 取域?qū)ο笾械膌ocation屬性 --> </body> </html>效果是一樣的
EL內(nèi)置對象
與JSP類似,EL表達(dá)式也有一些內(nèi)置對象可以直接拿來使用,它們都是
-
pageScope:JSP中的pageContext域?qū)ο?/p>
-
requestScope:JSP中的request域?qū)ο?/p>
-
sessionScope:JSP中的session域?qū)ο?/p>
-
applicationScope:JSP中的application域?qū)ο?/p>
-
param:是一個Map<String,String>,里面存儲了request中的全部參數(shù)。如${param.user}相當(dāng)于request.getParameter("user")
-
paramValues:和param類似,不過它是一個Map<String,String[]>,假設(shè)查詢參數(shù)name有多個值,則可以通過paramValues來獲取多個值,param則只會取第一個值
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> param: ${param.name} <br/> paramValues: ${paramValues.name[0]}, ${paramValues.name[1]} </body> </html> -
initParam:獲取初始化參數(shù),相當(dāng)于ServletContext.getInitParameter
示例如下
web.xml中配置初始化參數(shù)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><context-param><param-name>name</param-name><param-value>jack</param-value></context-param> </web-app>JSP中獲取初始化參數(shù)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> initParam: ${initParam.name} </body> </html>訪問
-
header:請求頭,是一個Map<String,String>
示例如下
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> accept: ${header.accept} <br/> user-agent: ${header["user-agent"]} <br/> </body> </html>訪問
-
headerValues:與header類似,不過它是個Map<String, String[]>,當(dāng)某一請求頭部有多個值時,可用該對象獲取
-
cookie:獲取請求中攜帶的Cookie
示例如下
JSP文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <% response.addCookie(new Cookie("rookie", "我這塊小餅干叫rookie"));%> cookieName: ${cookie.rookie.name} <br/> cookieValue: ${cookie.rookie.value} </body> </html>第一次訪問時,沒有Cookie
第二次訪問時,會攜帶第一次訪問得到的Cookie
第二次訪問時的抓包
-
pageContext:與JSP的pageContext對象是同一個,可以用它來獲取JSP的其他對象,如request,response,session,servletContext,servletConfig等對象。注意,EL中只有pageContext內(nèi)置對象,其他那些對象只能通過pageContext來獲取,比如${pageContext.request.contextPath}
EL取值方式
EL表達(dá)式進行取值時,會先嘗試匹配內(nèi)置對象,若沒有匹配到內(nèi)置對象,則再從4大作用域?qū)ο笾腥≈?#xff0c;示例如下
${param.name} <!-- 相當(dāng)于request.getParameter("name") --> ${hi} <!-- 內(nèi)置對象中沒有叫hi的,故嘗試從作用域?qū)ο笾腥≈?-->從作用域?qū)ο笾腥≈禃r,先從作用域范圍小的對象中取,若沒取到,再去作用域范圍更大的對象中取。4大作用域?qū)ο蟮姆秶鷱男〉酱笠来问?#xff1a;pageContext,request,session,application
也可以明確指定取某個域?qū)ο笾械膶傩?#xff0c;比如${sessionScope.userId}。注意,JSP中的4大域?qū)ο蟮拿Q,和EL中的有所不同
下面是用于驗證的JSP代碼
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %> <html> <body> <!-- 使用el表達(dá)式獲取數(shù)據(jù)的順序 --> <%pageContext.setAttribute("hi","hi, pageContext");request.setAttribute("hi","hi, request");session.setAttribute("hi","hi, session");application.setAttribute("hi","hi, application"); %> hi : ${hi}<br/> <!-- 會取到pageContext中的hi屬性 -->pageContext: ${pageScope.hi}<br/> <!-- 明確指定取 pageContext域?qū)ο笾械膆i --> request : ${requestScope.hi}<br/> <!-- 明確指定取 request域?qū)ο笾械膆i --> session: ${sessionScope.hi}<br/> application: ${applicationScope.hi}<br/> </body> </html>訪問
域?qū)ο笾械膶傩?#xff0c;也可以設(shè)置為Java對象,比如,有如下的類User和Address
public class User {private String name;private Address address;// 省略構(gòu)造函數(shù), get/set函數(shù),toString函數(shù)等 } public class Address {private String province;private String city;private String town;// 省略構(gòu)造函數(shù), get/set函數(shù),toString函數(shù)等 }JSP中進行如下設(shè)置
<%@ page import="po.User" %> <%@ page import="po.Address" %> <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %> <html> <body> <%Address address = new Address("四川","綿陽","江油");User user = new User("yogurt", address);request.setAttribute("user", user); %>name : ${user.name} <br/> <!-- 也可以用 ${user["name"]} --> address: <br/> - province: ${user.address.province} <br/> <!-- 也可以用 ${user["address"]["province"]} --> - city: ${user.address.city} <br/> - town: ${user.address.town} <br/> </body> </html>訪問
取JavaBean中的屬性,可以用點號.,后面接屬性的名稱,當(dāng)然也可以用[],括號內(nèi)是屬性的名稱(用雙引號括起來)
取Map中的值也是如此,只是傳遞的不是屬性名稱,而是key。
取數(shù)組或者List中的值,則是用[]加上元素下標(biāo)
除了支持取值,EL表達(dá)式還能進行一些基本的算術(shù)和邏輯運算,比如
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %> <html> <body> ${1+2}<br/> ${1-2}<br/> ${1*2}<br/> ${1/2}<br/> ${1%2}<br/> ${1>2}<br/> ${1>2?"南":"鋁"}<br/> ${1+"2"}<br/> <!-- 會自動將字符串2轉(zhuǎn)為數(shù)字,進行運算,而不是做字符串拼接 --> ${true && false} <!-- 支持邏輯運算 --> </body> </html>JSP動作元素
JSP指令是在JSP編譯時執(zhí)行,而JSP動作元素是在處理請求時執(zhí)行。可以用JSP動作元素動態(tài)導(dǎo)入頁面文件,獲取JavaBean,進行頁面轉(zhuǎn)發(fā)等
- <jsp:forward>:頁面轉(zhuǎn)發(fā)
- <jsp:include>:頁面動態(tài)導(dǎo)入
- <jsp: useBean>:尋找或?qū)嵗粋€JavaBean
- <jsp:setProperty>:設(shè)置JavaBean中的屬性
- <jsp:getProperty>:獲取JavaBean中的屬性
- …
其他一些已經(jīng)不怎么使用的元素就不一一列出
JSTL標(biāo)簽庫
當(dāng)需要在JSP頁面中,對EL表達(dá)式編寫一些邏輯判斷時,若直接嵌入Java代碼,則使得邏輯代碼和頁面展示耦合在一起,代碼可讀性變差,JSTL標(biāo)簽庫就是用來改善這種問題的。
JSTL是對EL的擴展,下面對JSTL的使用做簡單說明。首先需要進行JSTL的相關(guān)配置。
配置
首先,下載JSTL標(biāo)簽庫依賴,下載地址:http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/,拉到頁面最下方,下載最新的版本即可,或者直接使用http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/jakarta-taglibs-standard-1.1.2.zip
解壓后,在lib目錄中找到j(luò)stl.jar和standard.jar
將這兩個jar包添加到項目的依賴項中
在項目左側(cè)的External Library 中看到有如下2個包,則引入成功
在JSP頁面,通過<%@taglib %>來引入JSTL標(biāo)簽,引入方式如下
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>引入后,即可在JSP頁面中,用前綴c,來使用JSTL標(biāo)簽,如下(前綴c是自定義的,不是固定為c,可以為其他任何命名,通常命名為c,表示core,JSTL的核心庫,JSTL除了core核心庫,還有一些其他庫)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head><title>Title</title> </head> <body> <c:out value="xixi"/> </body> </html>如果在IDEA中,發(fā)現(xiàn)<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
這一行代碼標(biāo)紅,則添加如下配置
左上角 File -> Settings -> Language & Framework -> Schemas and DTDs -> 點擊 + 號
URI填寫 JSTL的DTD地址,File選擇先前下載的 jakarta-taglibs-standard包中的tld目錄下的c.tld
點擊Apply
若啟動程序后,訪問JSP頁面,發(fā)現(xiàn)如下報錯
其實是部署的web項目中,沒有standara.jar包中的文件
我們點擊左上角 File -> Project Structure -> Artifacts ,能看到提示說 standard.jar is missing
我們直接點擊右側(cè)的 Fix,選擇第二個,將所有缺失的依賴jar包添加進去即可
最后點擊 Apply,展開WEB-INF下的lib目錄,看到已經(jīng)將 jstl.jar和standard.jar添加了進去
再次啟動服務(wù),訪問對應(yīng)頁面,成功
至此,JSTL標(biāo)簽配置完成,下面可以進行JSTL的開發(fā)
使用
JSTL的標(biāo)簽主要有以下幾類
- 核心標(biāo)簽庫
- 格式化標(biāo)簽庫
- 函數(shù)標(biāo)簽庫
- XML標(biāo)簽庫
- SQL標(biāo)簽庫
其中,核心標(biāo)簽庫,格式化標(biāo)簽庫是最常用,其余的了解即可
下面對核心標(biāo)簽庫中的標(biāo)簽進行簡要介紹
-
<c:out>
輸出標(biāo)簽。有2個屬性
- value:輸出的值
- default:輸出值缺失的情況下的默認(rèn)值
示例:<c:out value="xixi" default="default"/>
-
<c:set>
向域?qū)ο笾刑砑訉傩浴S?個屬性
- var:屬性的key
- value:屬性的值
- scope:添加到哪個域?qū)ο?#xff08;若不指定,默認(rèn)添加到pageContext)
示例:<c:set var="name" value="yogurt" scope="request"/>
<c:set var="name" value="yogurt"/> <!-- 相當(dāng)于 pageContext.setAttribute("name","yogurt") --> <% request.setAttribute("name","amber"); %> <c:out value="${name}"/> <!-- 這里輸出的應(yīng)該是 yogurt 還是 amber 呢=> 是 yogurt, 因為 c:set 標(biāo)簽當(dāng)不指定 scope 時,默認(rèn)是向 pageContext作用域?qū)ο笾性O(shè)置屬性, pageContext域?qū)ο蠓秶∮趓equest, 所以EL表達(dá)式優(yōu)先取到pageContext中的值 --> -
<c:remove>
從域?qū)ο笾袆h除屬性。有2個屬性
- var:需要刪除的屬性的key
- scope:刪除的是哪個域?qū)ο笾械膶傩?#xff08;若不指定,則默認(rèn)刪除所有域?qū)ο笾械脑搶傩?#xff09;
示例:<c:remove var="userId" scope="request"/>
-
<c:if>
相當(dāng)于Java中的if代碼塊。有3個屬性
- test:條件表達(dá)式。當(dāng)該表達(dá)式為true時,會執(zhí)行<c:if>標(biāo)簽體里面的內(nèi)容
- var:通過該屬性,可以將條件表達(dá)式的計算結(jié)果保存在某一個變量中
- scope:與var一起使用,條件表達(dá)式結(jié)果保存在哪個域?qū)ο蟮膶傩灾?/li>
示例:
<c:set var="a" value="10"/> <c:if test="${a > 5}" var="result" scope="request"><h1>a = ${a} ,test is true, JSTL is easy</h1> </c:if> <% out.print("上面的c:if標(biāo)簽的條件表達(dá)式的結(jié)果是" + request.getAttribute("result")); %> -
<c:choose>
相當(dāng)于Java中的switch。這個標(biāo)簽有2個子標(biāo)簽<c:when>,<c:otherwise>
示例:
<c:set var="age" value="15"/> <c:choose><c:when test="${age < 10}"><h1>小孩</h1></c:when><c:when test="${age < 20}"><h1>少年</h1></c:when><c:when test="${age < 30}"><h1>青年</h1></c:when><c:when test="${age < 40}"><h1>中年</h1></c:when><c:otherwise><h1>不知道</h1></c:otherwise> </c:choose> -
<c:forEach>
循環(huán)標(biāo)簽。該標(biāo)簽運用較多。它有如下幾個屬性
- begin:起始位置下標(biāo)
- end:結(jié)束位置下標(biāo)(inclusive)
- step:步長
- varStatus:循環(huán)狀態(tài)
- var:該輪循環(huán)的元素
- items:用來遍歷的集合
示例
<!-- 循環(huán)標(biāo)簽 --> <%List<String> list = new ArrayList<>();list.add("a1");list.add("a2");list.add("a3");list.add("a4");list.add("a5");list.add("a6");request.setAttribute("list", list); %> <c:forEach begin="0" end="3" step="1" varStatus="status" var="element" items="${list}"><!--begin 起始下標(biāo)end 終止下標(biāo)(inclusive)step 步長如上面 begin=0 , end=3 , step=1, 其實相當(dāng)于 java 中的 for(int i = 0 ; i <= 3; i++)--><!-- varStatus 表示循環(huán)的狀態(tài), 其中有這么些值 -->index=${status.index} ---count=${status.count} ---step=${status.step} ---begin=${status.begin} ---end=${status.end} ---current=${status.current} ---first=${status.first} ---last=${status.last}element = ${element} <br/><!-- items 表示要迭代的集合 --><!-- var 表示的是集合中某一次迭代的元素 --><!-- 通常進行循環(huán)只需要使用 items 指定要迭代的集合, 以及 var 存放每一輪迭代的元素, 即可, 若要獲取某一輪迭代的相關(guān)變量, 如下標(biāo), 則可以用 varStatus, 而其他的屬性如 begin, end, step 不是很常用 --> </c:forEach>
下面展示一個綜合示例,使用JSTL標(biāo)簽進行動態(tài)表格繪制
<%Map<String, Student> student = new HashMap<>();Student s1 = new Student("Yogurt", "24", "2", "Excellent");Student s2 = new Student("Dick", "27", "3", "Good");Student s3 = new Student("Bob", "26", "4", "Medium");Student s4 = new Student("Amber", "25", "2", "Excellent");student.put(s1.name, s1);student.put(s2.name, s2);student.put(s3.name, s3);student.put(s4.name, s4);request.setAttribute("student", student); %> <c:if test="${student != null}"><table border="1px"><tr><th>name</th><th>age</th><th>grade</th><th>level</th></tr><c:forEach items="${student}" var="one"><tr><td>${one.value.name}</td> <!-- 注意, 這里獲取 Student 中的 name 屬性, 是通過 getName 方法去獲取的, 下面獲取其他屬性同理, 如不添加 get 方法, 訪問該 JSP 時, 會報錯 --><td>${one.value.age}</td><td>${one.value.grade}</td><td>${one.value.level}</td></tr></c:forEach></table> </c:if>總結(jié)
以上是生活随笔為你收集整理的重学JavaWeb —— JSP,简单全面一发入魂的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正确使用自旋锁、互斥锁
- 下一篇: Composure视口的材质丢失?