第 02 章 JSP
該部分代碼在webapp-serlet中的jsp頁面中展示暇唾;
JSP概述
什么叫JSP纯露?JSP的全稱叫(Java Server Page)剿骨,是一種動態(tài)網(wǎng)頁開發(fā)技術(shù)。它使用JSP標(biāo)簽在HTML網(wǎng)頁中插入Java代碼埠褪。標(biāo)簽通常以<%
開頭以%>
結(jié)束浓利。
JSP是一種Java servlet,主要用于實現(xiàn)Java web應(yīng)用程序的用戶界面部分钞速。網(wǎng)頁開發(fā)者們通過結(jié)合HTML代碼贷掖、XHTML代碼、XML元素以及嵌入JSP操作和命令來編寫JSP渴语。
JSP通過網(wǎng)頁表單獲取用戶輸入數(shù)據(jù)苹威、訪問數(shù)據(jù)庫及其他數(shù)據(jù)源,然后動態(tài)地創(chuàng)建網(wǎng)頁驾凶。
JSP標(biāo)簽有多種功能牙甫,比如訪問數(shù)據(jù)庫、記錄用戶選擇信息调违、訪問JavaBeans組件等窟哺,還可以在不同的網(wǎng)頁中傳遞控制信息和共享信息。
簡單理解有以下兩點:
- 運行在服務(wù)器端的Java頁面
- 使用HTML嵌套Java代碼實現(xiàn)翰萨。
JSP最大優(yōu)勢就是安全,這是前后端分離無法做到的糕殉。這是因為JSP有一個編碼的過程亩鬼,這個過程可以阻擋很多攻擊。前后端分離只是一個趨勢阿蝶,并不能代表JSP是弱勢的雳锋。比如下面的圖片,其注冊頁面仍是https://epass.icbc.com.cn/regist/regist_index.jsp
JSP羡洁。
工作原理
瀏覽器通過網(wǎng)絡(luò)訪問服務(wù)器后玷过,服務(wù)器需要對JSP頁面進(jìn)行編譯,編譯成類似HTML文件,而實際上最終把它變成Java代碼辛蚊,因為只有Java才能訪問數(shù)據(jù)庫等其他操作粤蝎。
關(guān)于如何查看JSP編譯后的文件,請看【TIP】中的第2點袋马。
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;
}
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
// 獲取響應(yīng)輸出流對象為null
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 {
// 設(shè)置響應(yīng)輸出流的ContentType類型虑凛,并設(shè)置編碼為UTF8碑宴。
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();
// 獲取響應(yīng)輸出流對象
out = pageContext.getOut();
_jspx_out = out;
// 設(shè)置輸出字符串結(jié)構(gòu),也就是HTML的結(jié)構(gòu)
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(" ");
out.print("hello jsp桑谍!啊哈哈");
out.write("\n");
out.write("</body>\n");
out.write("</html>\n");
} 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);
}
}
上面一段代碼就是JSP頁面編譯后的結(jié)果延柠。所以JSP的本質(zhì)就是Java代碼,就是Servlet锣披。<font style="color:red">在正常請求后贞间,JSP才會執(zhí)行編譯這個過程。</font>
在Servlet中盈罐,所謂的Html就是輸出將HTML標(biāo)簽輸出到瀏覽器榜跌,由瀏覽器下載下來,才能執(zhí)行盅粪。就像其他普通的網(wǎng)頁一樣钓葫,您的瀏覽器發(fā)送一個 HTTP 請求給服務(wù)器。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%="hello jsp票顾!啊哈哈"%>
<%out.println("我就是看看怎么輸出字符串");%>
</body>
</html>
- Web 服務(wù)器識別出這是一個對 JSP 網(wǎng)頁的請求础浮,并且將該請求傳遞給 JSP 引擎。通過使用 URL解析或者 .jsp 文件來完成奠骄。
- JSP 引擎從磁盤中載入 JSP 文件豆同,然后將它們轉(zhuǎn)化為 Servlet。這種轉(zhuǎn)化只是簡單地將所有模板文本改用 println() 語句含鳞,并且將所有的 JSP 元素轉(zhuǎn)化成 Java 代碼影锈。
- JSP 引擎將 Servlet 編譯成可執(zhí)行類,并且將原始請求傳遞給 Servlet 引擎蝉绷。
- Web 服務(wù)器的某組件將會調(diào)用 Servlet 引擎鸭廷,然后載入并執(zhí)行 Servlet 類。在執(zhí)行過程中熔吗,Servlet 產(chǎn)生 HTML 格式的輸出并將其內(nèi)嵌于 HTTP response 中上交給 Web 服務(wù)器辆床。
- Web 服務(wù)器以靜態(tài) HTML 網(wǎng)頁的形式將 HTTP response 返回到您的瀏覽器中。
- 最終桅狠,Web 瀏覽器處理 HTTP response 中動態(tài)產(chǎn)生的HTML網(wǎng)頁讼载,就好像在處理靜態(tài)網(wǎng)頁一樣烫堤。
【TIPS】
-
在開發(fā)過程中耙册,修改靜態(tài)資源和JSP,是不需要重啟服務(wù)的。在Idea中灭红,只需要使用快捷鍵
ctrl
+D
健盒,如下圖赤屋,選擇update classes and resources
即可园骆。
Idea 運行Tomcat后,編譯JSP文件存放的目錄在
/Users/{用戶名}/Library/Caches/JetBrains/IntelliJIdea{版本號}/tomcat/{項目名稱}/work/Catalina/localhost/webapp_serlet/org/apache/jsp/
(mac系統(tǒng)中)津滞。-
在使用tomcat 9.0版本時铝侵,發(fā)了一個錯誤(警告),錯誤如以下:
org.apache.jasper.servlet.TldScanner.scanJars 至少有一個JAR被掃描用于TLD但尚未包含TLD触徐。 為此記錄器啟用調(diào)試日志記錄咪鲜,以獲取已掃描但未在其中找到TLD的完整JAR列表。 在掃描期間跳過不需要的JAR可以縮短啟動時間和JSP編譯時間撞鹉。
只需要將Tomcat下面的配置文件目錄conf/catalina.properties
中的tomcat.util.scan.StandardJarScanFilter.jarsToSkip=/
改成*.jar
即可疟丙,如下所示tomcat.util.scan.StandardJarScanFilter.jarsToSkip=*.jar annotations-api.jar,\ ant-junit*.jar,\ ant-launcher.jar,\ ... xmlParserAPIs-*.jar,\ xmlParserAPIs.jar,\ xom-*.jar
再重啟tomcat服務(wù)即可。
-
關(guān)于Servlet編譯JSP的命令規(guī)范鸟雏,首先將
index.jsp
文件找到后享郊,編譯后的文件則命名為index_jsp.java
文件以及index_jsp.class
文件,如下圖所示孝鹊。
JSP實現(xiàn)輸出
該部分代碼在webapp-serlet中的demo01中展示炊琉;
關(guān)于JSP的局部申明與全局申明
-
<% code %>
是申明局部變量;局部指的是jspjava文件中的_jspService()
方法內(nèi)又活。- 不可以對變量使用修飾符苔咪。
- 不可以定義方法。
-
<%! code %>
是申明全局變量柳骄;- 申明全局變量团赏,可以在當(dāng)前的頁面任意位置進(jìn)行調(diào)用;
- 可以創(chuàng)建對應(yīng)的方法耐薯,以及變量舔清。
比如,在下面的jsp頁面中曲初,
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>
<%
String str = "歡迎來到JSP World体谒!";
for (int i = 0; i < 3; i++) {
out.println("<font style='color:red'>"+str+"</font>");
test();
}
%>
</h1>
<%-- 等價于out.println(str);--%>
<%=str%>
<%=PATH%>
<%-- 申明全局變量 --%>
<%!
<%-- 申明全局變量 --%>
private static final String PATH=System.lineSeparator();
<%-- 申明全局方法 --%>
public void test(){
System.out.println("這是一個全局方法!");
}
%>
</body>
</html>
下面將Servlet引擎編譯后的JSP复斥,indexjsp.java文件如下:
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
// 申明的全局變量
private static final String PATH=System.lineSeparator();
// 申明的全局方法
public void test(){
System.out.println("這是一個全局方法营密!");
}
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;
}
}
// 此處省略部分代碼
....
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("\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(" <h1>\n");
out.write(" ");
String str = "歡迎來到JSP World评汰!";
for (int i = 0; i < 3; i++) {
out.println("<font style='color:red'>"+str+"</font>");
test();
}
out.write("\n");
out.write(" </h1>\n");
out.write(" ");
out.write("\n");
out.write(" ");
out.print(str);
out.write("\n");
out.write(" ");
out.print(PATH);
out.write("\n");
out.write("\n");
out.write(" ");
out.write("\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
......
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
從上編譯的文件,可以看出我們之前剛剛所提的局部變量與全局變量的問題痢虹。局部變量是在_jspService()
方法內(nèi)的被去,而全局變量則是index_jsp
類中的。
關(guān)于應(yīng)用服務(wù)狀態(tài)
404錯誤
404錯誤---找不到訪問的頁面或資源
- 運行時奖唯,URL輸入錯誤
- 將頁面放在WEB-INF下
- 外部啟動Tomcat惨缆,未部署項目
500錯誤
500錯誤----JSP頁面代碼有誤;
- JSP頁面代碼有錯誤
- 頁面無法顯示
-
未啟動Tomcat
jsp報異常丰捷,異常的分布包含在2個地方坯墨,一個是JSP頁面文件當(dāng)中的行數(shù),還有一個是生成的_jsp.java文件的行數(shù)病往,如下圖所示:
關(guān)于Page指令
通過屬性定義了JSP的特性捣染,實現(xiàn)與JSP容器的通信。
語法
<%@ page language="屬性值" import="屬性值" contentType="屬性值"%>
屬性 | 說明 |
---|---|
language | 指定JSP頁面使用的腳本語言 |
import | 通過該屬性來引用腳本語言中使用到的類文件 |
contentType | 用來指定頁面的MIME類型停巷,以及字符編碼方式 |
示例
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="com.ermao.servlet.entity.*" %>
<html>
<head>
<title>Title</title>
<%Person person = new Person();%>
<%=person%>
</head>
<body>
</body>
</html>
關(guān)于編碼
JSP有三個地方設(shè)置編碼耍攘,如下代碼所示:
<%@ page pageEncoding="UTF-8" language="java" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page import="com.ermao.servlet.entity.*" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<html>
<head>
<title>Title</title>
<meta content="text/html" charset="ISO-8859-1" />
</head>
<body>
<%
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
String dateStr = simpleDateFormat.format(date);
%>
<%Person person = new Person();%>
<%=person%>
<%=dateStr%>
</body>
</html>
- 是在
page
指令中設(shè)置:-
<%@ page pageEncoding="UTF-8" language="java" %>
是設(shè)置java文件的編碼,指令中所設(shè)置的<%@ page pageEncoding="UTF-8" %>
是頁面(或者說是index_jsp.java
這個java文件編碼格式)畔勤。 -
<%@ page contentType="text/html;charset=UTF-8" %>
是設(shè)置響應(yīng)輸出流的編碼格式蕾各,在index_jsp.java
編譯的java文件中,有一行代碼response.setContentType("text/html;charset=UTF-8");
庆揪,其中response
對象設(shè)置的contentType
式曲,屬于HTTP的響應(yīng)頭。是服務(wù)器往客戶端響應(yīng)(write()
往外輸出流的時候)是以什么樣的編碼格式輸出嚷硫。
-
- 是在HTML頁面中的
meta
標(biāo)簽中設(shè)置<meta content="text/html" charset="ISO-8859-1" />
检访,此處為瀏覽器從應(yīng)用服務(wù)中下載頁面后,以什么樣的編碼格式讀取文件仔掸,展示給瀏覽器客戶端錢前的用戶脆贵。
比如下面的亂碼形式:
-
pageEncoding
設(shè)置錯誤導(dǎo)致的亂碼
-
contentType
響應(yīng)輸出流編碼格式設(shè)置錯誤導(dǎo)致的亂碼
-
meta
設(shè)置錯誤的編碼,沒有造成亂碼起暮。
為了規(guī)避亂碼卖氨,三個編碼應(yīng)該保持一致。
關(guān)于out
- out對象
- out對象是JSP的內(nèi)置對象
- 無需實例化即可使用
- 實現(xiàn)數(shù)據(jù)的輸出顯示
- out對象是JSP的內(nèi)置對象
- out對象的方法
屬性 | 說明 |
---|---|
向頁面輸出顯示 | |
println | 向頁面輸出顯示负懦,在結(jié)尾處添加換行 |
jsp 最終通過響應(yīng)輸出
out
輸出(輸出一個text文本)筒捺,瀏覽器讀取的時候,首先通過inputStream纸厉,然后read(text)變成一個File f=File(in)
系吭。然后瀏覽器通過windows.load(f)
加載文件,然后再是document()
輸出颗品。
關(guān)于JSP內(nèi)置對象
以下內(nèi)容是JSP最核心肯尺,最重要沃缘,也是所有交互層概念當(dāng)中最最需要掌握的地方。
JSP本質(zhì)
在上面的內(nèi)容中则吟,已經(jīng)提到JSP的本質(zhì)就是Java槐臀。
JSP其實本質(zhì)是Java的Servlet,將HTML的編碼已文本流的方式交給客戶端氓仲,在HTML當(dāng)中我們實際看到的就是一個普通的前端頁面水慨。
JSP內(nèi)置對象
該部分代碼在webapp-serlet中的demo02中展示;
JSP內(nèi)置對象(隱式對象)是JSP容器為每個頁面提供的Java對象敬扛,開發(fā)者可以直接使用它們而不用顯式聲明晰洒。JSP隱式對象也被稱為預(yù)定義變量。
JSP所支持的九大內(nèi)置對象啥箭,如下表欢顷,其中標(biāo)記的對象必須重點掌握。
對象 | 描述 | 對象作用域 |
---|---|---|
request | <font style="color:red">HttpServletRequest 接口的實例</font> | 局部變量 |
response | <font style="color:red">響應(yīng)對象捉蚤,HttpServletResponse 接口的實例</font> | 局部變量 |
out | JspWriter類的實例抬驴,用于把結(jié)果輸出至網(wǎng)頁上 | |
session | <font style="color:red">HttpSession類的實例,會話對象缆巧,是從application對象中獲取布持。</font> | 局部變量 |
application | <font style="color:red">應(yīng)用程序?qū)ο螅琒ervletContext類的實例陕悬,與應(yīng)用上下文有關(guān)</font> | 局部變量 |
config | ServletConfig類的實例题暖,配置對象 | |
pageContext | PageContext類的實例,頁面上下文對象捉超,提供對JSP頁面所有對象以及命名空間的訪問 | |
page | 頁面對象胧卤,類似于Java類中的this關(guān)鍵字,只作用于JSP中拼岳。 | |
Exception | Exception類的對象枝誊,代表發(fā)生錯誤的JSP頁面中對應(yīng)的異常對象 |
Request對象
當(dāng)瀏覽器向服務(wù)器發(fā)起請求,那么瀏覽器本次請求所攜帶的所有信息惜纸,都包含在Request對象中叶撒。
request對象是javax.servlet.http.HttpServletRequest
類的實例。每當(dāng)客戶端請求一個JSP頁面時耐版,JSP引擎就會制造一個新的request對象來代表這個請求祠够。
request對象提供了一系列方法來獲取HTTP頭信息,cookies粪牲,HTTP方法等等古瓤。
比如下面兩個JSP頁面,register.jsp
(是一個注冊頁面)以及register-service.jsp
(服務(wù)端的一個頁面)腺阳。上述內(nèi)容均屬于引入說明落君。
register.jsp
頁面
<%-- 設(shè)置編碼格式 --%>
<%@ page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta content="text/html" charset="UTF-8">
<title>測試注冊頁面</title>
<script type="application/javascript" src="static/js/jquery-3.4.1.min.js"></script>
<link type="text/css" href="static/css/animate.css">
</head>
<body>
<div>
<form method="post" action="register-service.jsp">
<div>
<label>
<input name="user" type="text" placeholder="用戶名" />
</label>
</div>
<div>
<label>
<input name="password" type="password" placeholder="密碼" />
</label>
</div>
<div>
<button type="submit">提交</button>
</div>
</form>
</div>
</body>
</html>
register-service.jsp
頁面
<%-- 設(shè)置編碼格式 --%>
<%@ page pageEncoding="UTF-8" contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
<meta content="text/html" charset="UTF-8">
<title>Title</title>
</head>
<body>
<%
String user = request.getParameter("user");
String password = request.getParameter("password");
%>
<%=user%>
<%=password%>
</body>
</html>
當(dāng)請求抵達(dá)指定頁面后滴须,需要從Request對象中的getParamter(String paramterName)
獲取請求參數(shù)。
獲取復(fù)數(shù)形式的選項則使用getParameterValues(String paramterName)
叽奥,比如checkbox等。
關(guān)于GET與POST請求
在Http請求中痛侍,存在兩種請求數(shù)據(jù)的方式朝氓,如下所示:
- GET(默認(rèn)):希望從服務(wù)器獲取數(shù)據(jù)
- POST:希望向服務(wù)器提交數(shù)據(jù)
比較項 | get | post |
---|---|---|
參數(shù)出現(xiàn)在URL中 | 是 | 否 |
長度限制 | 有 | 無 |
安全性 | URL低(暴露請求參數(shù)) | URL安全高(未直接暴露請求參數(shù)) |
URL可傳播 | 是 | 否 |
而Http請求使用的Http協(xié)議,但是Http協(xié)議又是明文協(xié)議主届,而Http的密文協(xié)議就是Https赵哲,使用SSL進(jìn)行加密。
請求類型的安全不是指Http的報文的安全君丁,而是請求的參數(shù)是否暴露在URL地址中枫夺。
Request常用方法
方法名稱 | 說明 |
---|---|
String getParameter(String name) |
根據(jù)表單組件名稱獲取提交數(shù)據(jù) |
String[ ] getParameterValues(String name) |
獲取表單組件對應(yīng)多個值時的請求數(shù)據(jù),如checkbox等 |
void setCharacterEncoding(String charset) |
指定每個請求的編碼 |
RequestDispatcher getRequestDispatcher(String path) |
返回一個RequestDispatcher對象绘闷,該對象的forward( ) 方法用于轉(zhuǎn)發(fā)請求 |
關(guān)于提交數(shù)據(jù)中文亂碼
該部分代碼在webapp-serlet中的demo02中展示橡庞;
<font style="color:red;font-weight:bolder;">JSP默認(rèn)的數(shù)據(jù)傳輸編碼是ISO-8859-1
,而不是UTF-8
</font>印蔗。所以在表單中扒最,如果進(jìn)行中文傳輸,將會有亂碼的現(xiàn)象發(fā)生华嘹。下面將初步介紹如何解決中亂碼的問題吧趣。
- POST請求解決中文亂碼,使用
request.setCharaterEncoding("UTF-8")
來解決中文亂碼耙厚。 - get請求中解決中文亂碼方式有以下3種:
- 對于某個獲取參數(shù)的進(jìn)行重新編碼强挫,如
String str = new String(request.getParamter("user").getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8)
。這種方式治標(biāo)不治本薛躬。解決不了根本的亂碼問題俯渤。 - 下面介紹的兩種方式,均是在tomcat配置目錄下的
conf/server.xml
中進(jìn)行配置<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
型宝。-
對tomcat目錄中的配置
conf/server.xml
添加配置URIEncoding="UTF-8"
這種方式很粗暴稠诲。將影響一些不需要的轉(zhuǎn)碼字符也被轉(zhuǎn)碼。<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
-
在tomcat配置目錄下的
conf/server.xml
還有一種GET請求轉(zhuǎn)碼诡曙,就是添加useBodyEncodingForURI="true"
只有配置了該屬性才會在GET請求中才會生效臀叙。不對項目做任何的字符集限制,可以針對性對request.setCharaterEncoding("UTF-8")
价卤。<font style="color:red;font-weight:bolder;">如果在未設(shè)置useBodyEncodingForURI="true"
的前提下劝萤,單獨使用request.setCharaterEncoding("UTF-8")
將是不會對GET傳參進(jìn)行轉(zhuǎn)碼解碼的,只會對POST的傳參進(jìn)行解碼轉(zhuǎn)碼慎璧。</font><Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>
<font style="color:red;font-weight:bolder;">需要配合進(jìn)行使用
request.setCharaterEncoding("UTF-8")
床嫌;比如跨释,某些頁面需要單獨設(shè)置其他編碼,那么就可以通過這種方式實現(xiàn)厌处。</font>
-
- 對于某個獲取參數(shù)的進(jìn)行重新編碼强挫,如
JSP解決中亂碼的總體原則就是:<font style="color:red;font-weight:bolder;">保證整個項目當(dāng)中鳖谈,所有文件(文件、文件流)的字符集統(tǒng)一阔涉!</font>
屬性轉(zhuǎn)交
該部分代碼在webapp-serlet中的demo03中展示缆娃;驗證屬性的轉(zhuǎn)交,頁面轉(zhuǎn)交過程瑰排。是又
index.jsp
輸入表單贯要,get_form_service.jsp
接受表單數(shù)據(jù),再設(shè)置屬性椭住,get_attribute.jsp
來獲取屬性崇渗。同時結(jié)合轉(zhuǎn)發(fā)和重定向。
當(dāng)請求到達(dá)后臺后京郑,可以從request.getParameter(String param)
拿取一次數(shù)據(jù)宅广,而其他的JSP頁面則無法獲取到本次的傳遞的參數(shù),除非是同一個request請求些举,否則無法獲取相關(guān)的參數(shù)乘碑。如果其他JSP頁面需要進(jìn)行數(shù)據(jù)流轉(zhuǎn)(數(shù)據(jù)處理)時,需要將數(shù)據(jù)發(fā)送出去金拒,那么將處理后的數(shù)據(jù)當(dāng)做request對象中的屬性保存(通過設(shè)置request.setAttribute(String name,Object obj)
)兽肤,方便數(shù)據(jù)的傳輸。其他的JSP頁面則通過request.getAttribute(String name)
來獲取之前JSP處理后的數(shù)據(jù)绪抛。比如资铡,判斷是否登錄(也可以通過Session來完成)。
當(dāng)從Attribute
中獲取屬性時幢码,必須強轉(zhuǎn)返回數(shù)據(jù)笤休。因為setAttribute(String name ,Object obj)
。而getAttribute(String name)
時症副,則返回的是Object
對象店雅。需要將返回值強轉(zhuǎn)為自己需要的類型。
<font style="color:red;font-weight:bolder;">
注意:
- 使用屬性值的時候要做非空判斷贞铣,否則會出現(xiàn)空指針異常闹啦。
- 他的返回值類型是Object類型,需要做數(shù)據(jù)類型的轉(zhuǎn)換辕坝。
</font>
Session對象
在客戶端(一般是指瀏覽器)和服務(wù)器之間建立會話后(建立長連接[1])窍奋,會在該會話當(dāng)中,產(chǎn)生若干次請求和響應(yīng)。
客戶端和服務(wù)器之間的交互琳袄,只可能是客戶端對服務(wù)器進(jìn)行輪訓(xùn)江场,而服務(wù)器時無法主動尋找客戶端進(jìn)行數(shù)據(jù)推送的。
Session的特點
- Session可以保存屬性窖逗,保留數(shù)據(jù)(比如址否,記錄用戶的登錄狀態(tài))
- 第一次請求到達(dá)服務(wù)器后,服務(wù)器將自動生成一個sessionId碎紊,并將該sessionId作為本地會話的唯一憑證(將session返回給瀏覽器)佑附。以后(第二次請求開始)該會話的每次請求,都會攜帶sessionId矮慕。
- 在正常且不超時的情況下,只要瀏覽器不關(guān)閉啄骇,session就不會中斷痴鳄。
- Session可以作為服務(wù)器和客戶端的一次會話緩存
- Session為客戶端用戶獨享。
- Session默認(rèn)無操作的情況下保留sessionId 30分鐘(一般情況下不會去修改)缸夹。
- session的數(shù)據(jù)是在服務(wù)器端的痪寻,服務(wù)器保存的會話數(shù)據(jù)量(產(chǎn)生數(shù)據(jù)冗余)會越來越大,從而導(dǎo)致性能問題虽惭。
若Session沒有清理機制橡类,會導(dǎo)致性能問題或服務(wù)器崩潰,所有在調(diào)用Session時芽唇,當(dāng)會話結(jié)束后顾画,程序應(yīng)該做到以下兩點:
- 程序主動清除session數(shù)據(jù),比如退出登錄時匆笤,清楚sessionId等數(shù)據(jù)研侣。
- 服務(wù)器主動清除長時間沒有再次發(fā)出請求的session。
Session的調(diào)用
調(diào)用session的設(shè)置方法炮捧。
public void setAttribute(String name, Object value)
session.setAttribute("userName", "張三豐");
調(diào)用設(shè)置session的屬性的方法庶诡。
public Object getAttribute(String name);
userName=(String)session.getAttribute("userName");
獲取sessionId。
public String getId();
session.getId();
關(guān)于清除數(shù)據(jù):
- 設(shè)置會話失效
session.invalidate();
- 移除會話的某個屬性:
session.removeAttribute(String attributeName);
Application對象
比如實現(xiàn)統(tǒng)計每個用戶訪問次數(shù)
- 整個服務(wù)共享數(shù)據(jù)咆课,所有的用戶都可以獲取這里的數(shù)據(jù)
Cookie
- 將數(shù)據(jù)保存在客戶端末誓;
- 保存的上限是7天
- 存在的極大的安全的隱患
- 用戶是可以禁止Cookie的
- Cookie第一次請求服務(wù)端,如果服務(wù)端沒有生成SessionId书蚪,將會由客戶端生成一個SessionId交給服務(wù)器喇澡。
- 不能將敏感的數(shù)據(jù)存放在cookie里面。
對象的作用域
對象 | 作用域[2] |
---|---|
Page | 只作用域當(dāng)前的JSP(Servlet中不存在JSP) |
Request | 作用于一次請求 |
Session | 作用于一次會話 |
Application | 作用于整個工程 |
轉(zhuǎn)發(fā)和重定向
轉(zhuǎn)發(fā)
轉(zhuǎn)發(fā)方式
轉(zhuǎn)發(fā)有兩種方式:
- 使用
Request
中的方法RequestDispatcher
對象殊校,語法如下:// request對象和response對象 request.getRequestDispatcher("url").forward(request, response)
- 使用
forword()
方法進(jìn)行重定向撩幽。語法如下所示:<jsp:forword page="url" />
轉(zhuǎn)發(fā)工作方式
從上圖可以看出,轉(zhuǎn)發(fā)是客戶端發(fā)送一次請求到服務(wù)器后,服務(wù)器交給JSP頁面(但是當(dāng)前JSP頁面無法處理)窜醉,將把本地請求轉(zhuǎn)交給其他的URL或JSP頁面進(jìn)行處理宪萄。可以在轉(zhuǎn)發(fā)的地址中獲取請求的參數(shù)(可直接獲取"getParameter(String paramter)
")榨惰。
總結(jié)如下:
- 所有的數(shù)據(jù)流轉(zhuǎn)拜英,全部再后臺完成。
- 用戶只有一次請求琅催,并獲得一次響應(yīng)居凶。
- URL是有沒有任何變化的。
- 轉(zhuǎn)發(fā)是將請求和響應(yīng)一并帶走藤抡,也就意味著他可以獲取原本
request
對象中所有的參數(shù)和數(shù)據(jù)侠碧。 - 轉(zhuǎn)發(fā)是不能轉(zhuǎn)發(fā)到工程(僅限定本地應(yīng)用)的外部資源的(本質(zhì)是從一個servlet跳轉(zhuǎn)到另一個servlet)。
重定向
重定向方式
通過調(diào)用response
對象中的sendRedirect(String url)
方法實現(xiàn)缠黍。如下所示:
response.sendRedirect(url);
經(jīng)過查閱資料弄兜,再提供下面兩種重定向的實現(xiàn)。
// 第一種重定向方式:
// 下面的參數(shù)中瓷式,
// refresh代表刷新頁面替饿,
// 5代表間隔多久刷新頁面(單位:秒)
// RedirectUrl代表的是重定向的地址
response.setHeader("refresh","5;URL=RedirectUrl")
// 第二種重定向方式:
response.setStatus(response.SC_MOVED_TEMPORARILY);
response.setHeader("Location", RedirectUrl);
重定向工作方式
- 轉(zhuǎn)發(fā)一次,將會通過響應(yīng)告訴客戶端重新請求服務(wù)器贸典。
- 原本的
request
和response
全部丟失视卢。將會產(chǎn)生新的request
和response
。 - 重定向既不攜帶請求的參數(shù)也不攜帶屬性廊驼。如果需要攜帶參數(shù)据过,只能通過
url
傳參或者SESSION
等其他方式進(jìn)行傳參。 - 重定向是可以重定向至任意資源的妒挎。
- 重定向?qū)?dǎo)致URL的變化蝶俱。
轉(zhuǎn)發(fā)和重定向的區(qū)別
URL變化 | 否 | 是 |
---|---|---|
重新發(fā)出請求 | 不會 | 會 |
是否攜帶請求 | 是 | 否 |
目標(biāo)URL要求 | 僅本W(wǎng)eb應(yīng)用 | 任意URL |
<font style="color:red;font-weight:bolder;">
重定向是客戶端行為,轉(zhuǎn)發(fā)是服務(wù)器行為饥漫!
</font>
關(guān)于Request榨呆、Session以及Application的對比
request
、session
庸队、application
者三個對象都可以存儲屬性积蜻。
對象 | 生命周期 |
---|---|
Request | 存儲的數(shù)據(jù)僅在一個請求中可用 |
Session | 存儲的數(shù)據(jù)在一個會話有效期內(nèi)可用 |
Application | 存儲的數(shù)據(jù)在整個Web項目中可用 |