第 02 章 JSP

第 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.jspJSP羡洁。

工商銀行

工作原理

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>

JSP執(zhí)行過程

在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>
  1. Web 服務(wù)器識別出這是一個對 JSP 網(wǎng)頁的請求础浮,并且將該請求傳遞給 JSP 引擎。通過使用 URL解析或者 .jsp 文件來完成奠骄。
  2. JSP 引擎從磁盤中載入 JSP 文件豆同,然后將它們轉(zhuǎn)化為 Servlet。這種轉(zhuǎn)化只是簡單地將所有模板文本改用 println() 語句含鳞,并且將所有的 JSP 元素轉(zhuǎn)化成 Java 代碼影锈。
  3. JSP 引擎將 Servlet 編譯成可執(zhí)行類,并且將原始請求傳遞給 Servlet 引擎蝉绷。
  4. Web 服務(wù)器的某組件將會調(diào)用 Servlet 引擎鸭廷,然后載入并執(zhí)行 Servlet 類。在執(zhí)行過程中熔吗,Servlet 產(chǎn)生 HTML 格式的輸出并將其內(nèi)嵌于 HTTP response 中上交給 Web 服務(wù)器辆床。
  5. Web 服務(wù)器以靜態(tài) HTML 網(wǎng)頁的形式將 HTTP response 返回到您的瀏覽器中。
  6. 最終桅狠,Web 瀏覽器處理 HTTP response 中動態(tài)產(chǎn)生的HTML網(wǎng)頁讼载,就好像在處理靜態(tài)網(wǎng)頁一樣烫堤。

【TIPS】

  1. 在開發(fā)過程中耙册,修改靜態(tài)資源和JSP,是不需要重啟服務(wù)的。在Idea中灭红,只需要使用快捷鍵ctrl+D健盒,如下圖赤屋,選擇update classes and resources即可园骆。

    Tips 1

  2. Idea 運行Tomcat后,編譯JSP文件存放的目錄在/Users/{用戶名}/Library/Caches/JetBrains/IntelliJIdea{版本號}/tomcat/{項目名稱}/work/Catalina/localhost/webapp_serlet/org/apache/jsp/(mac系統(tǒng)中)津滞。

  3. 在使用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ù)即可。

  4. 關(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ù)病往,如下圖所示:


    500錯誤

關(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>
  1. 是在page指令中設(shè)置:
    1. <%@ page pageEncoding="UTF-8" language="java" %>是設(shè)置java文件的編碼,指令中所設(shè)置的<%@ page pageEncoding="UTF-8" %>是頁面(或者說是index_jsp.java這個java文件編碼格式)畔勤。
    2. <%@ 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()往外輸出流的時候)是以什么樣的編碼格式輸出嚷硫。
  2. 是在HTML頁面中的meta標(biāo)簽中設(shè)置<meta content="text/html" charset="ISO-8859-1" />检访,此處為瀏覽器從應(yīng)用服務(wù)中下載頁面后,以什么樣的編碼格式讀取文件仔掸,展示給瀏覽器客戶端錢前的用戶脆贵。

比如下面的亂碼形式:

  1. pageEncoding設(shè)置錯誤導(dǎo)致的亂碼
    關(guān)于pageEncoding
  2. contentType響應(yīng)輸出流編碼格式設(shè)置錯誤導(dǎo)致的亂碼
    contentType響應(yīng)輸出流亂碼
  3. meta設(shè)置錯誤的編碼,沒有造成亂碼起暮。
    meta設(shè)置錯誤的編碼

為了規(guī)避亂碼卖氨,三個編碼應(yīng)該保持一致。

關(guān)于out

  • out對象
    • out對象是JSP的內(nèi)置對象
      • 無需實例化即可使用
    • 實現(xiàn)數(shù)據(jù)的輸出顯示
  • out對象的方法
屬性 說明
print 向頁面輸出顯示
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ā)生华嘹。下面將初步介紹如何解決中亂碼的問題吧趣。

  1. POST請求解決中文亂碼,使用request.setCharaterEncoding("UTF-8")來解決中文亂碼耙厚。
  2. get請求中解決中文亂碼方式有以下3種:
    1. 對于某個獲取參數(shù)的進(jìn)行重新編碼强挫,如String str = new String(request.getParamter("user").getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8)。這種方式治標(biāo)不治本薛躬。解決不了根本的亂碼問題俯渤。
    2. 下面介紹的兩種方式,均是在tomcat配置目錄下的conf/server.xml中進(jìn)行配置<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>型宝。
      1. 對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"/>
        
      2. 在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>

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;">
注意:

  1. 使用屬性值的時候要做非空判斷贞铣,否則會出現(xiàn)空指針異常闹啦。
  2. 他的返回值類型是Object類型,需要做數(shù)據(jù)類型的轉(zhuǎn)換辕坝。

</font>

Session對象

sesssion工作方式

在客戶端(一般是指瀏覽器)和服務(wù)器之間建立會話后(建立長連接[1])窍奋,會在該會話當(dāng)中,產(chǎn)生若干次請求和響應(yīng)。

客戶端和服務(wù)器之間的交互琳袄,只可能是客戶端對服務(wù)器進(jìn)行輪訓(xùn)江场,而服務(wù)器時無法主動尋找客戶端進(jìn)行數(shù)據(jù)推送的。

Session的特點
  1. Session可以保存屬性窖逗,保留數(shù)據(jù)(比如址否,記錄用戶的登錄狀態(tài))
    1. 第一次請求到達(dá)服務(wù)器后,服務(wù)器將自動生成一個sessionId碎紊,并將該sessionId作為本地會話的唯一憑證(將session返回給瀏覽器)佑附。以后(第二次請求開始)該會話的每次請求,都會攜帶sessionId矮慕。
    2. 在正常且不超時的情況下,只要瀏覽器不關(guān)閉啄骇,session就不會中斷痴鳄。
    3. Session可以作為服務(wù)器和客戶端的一次會話緩存
    4. Session為客戶端用戶獨享。
    5. Session默認(rèn)無操作的情況下保留sessionId 30分鐘(一般情況下不會去修改)缸夹。
  2. 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ù):

  1. 設(shè)置會話失效session.invalidate();
  2. 移除會話的某個屬性:session.removeAttribute(String attributeName);

Application對象

比如實現(xiàn)統(tǒng)計每個用戶訪問次數(shù)

  1. 整個服務(wù)共享數(shù)據(jù)咆课,所有的用戶都可以獲取這里的數(shù)據(jù)

Cookie

  1. 將數(shù)據(jù)保存在客戶端末誓;
  2. 保存的上限是7天
  3. 存在的極大的安全的隱患
  4. 用戶是可以禁止Cookie的
  5. Cookie第一次請求服務(wù)端,如果服務(wù)端沒有生成SessionId书蚪,將會由客戶端生成一個SessionId交給服務(wù)器喇澡。
  6. 不能將敏感的數(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ā)有兩種方式:

  1. 使用Request中的方法RequestDispatcher對象殊校,語法如下:
    // request對象和response對象
    request.getRequestDispatcher("url").forward(request, response)
    
  2. 使用forword()方法進(jìn)行重定向撩幽。語法如下所示:
    <jsp:forword page="url" />
    

轉(zhuǎn)發(fā)工作方式

轉(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é)如下:

  1. 所有的數(shù)據(jù)流轉(zhuǎn)拜英,全部再后臺完成。
  2. 用戶只有一次請求琅催,并獲得一次響應(yīng)居凶。
  3. URL是有沒有任何變化的。
  4. 轉(zhuǎn)發(fā)是將請求和響應(yīng)一并帶走藤抡,也就意味著他可以獲取原本request對象中所有的參數(shù)和數(shù)據(jù)侠碧。
  5. 轉(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);

重定向工作方式

重定向工作方式
  1. 轉(zhuǎn)發(fā)一次,將會通過響應(yīng)告訴客戶端重新請求服務(wù)器贸典。
  2. 原本的requestresponse全部丟失视卢。將會產(chǎn)生新的requestresponse
  3. 重定向既不攜帶請求的參數(shù)也不攜帶屬性廊驼。如果需要攜帶參數(shù)据过,只能通過url傳參或者SESSION等其他方式進(jìn)行傳參。
  4. 重定向是可以重定向至任意資源的妒挎。
  5. 重定向?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的對比

requestsession庸队、application者三個對象都可以存儲屬性积蜻。

對象 生命周期
Request 存儲的數(shù)據(jù)僅在一個請求中可用
Session 存儲的數(shù)據(jù)在一個會話有效期內(nèi)可用
Application 存儲的數(shù)據(jù)在整個Web項目中可用

  1. 長連接是服務(wù)器與服務(wù)器之間建立通訊的通道,其最底層實現(xiàn)就是socket彻消「筒穑可以實現(xiàn)服務(wù)端與客戶端只要通訊不中斷,那么服務(wù)器可以推送數(shù)據(jù)至客戶端宾尚,客戶端也可以主動請求服務(wù)端丙笋。 ?

  2. 作用域是指當(dāng)前數(shù)據(jù)可以作用的范圍(簡單的判斷方法谢澈,只要有setAttribute以及getAttribute這兩個方法一般屬于作用域)。 ?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末御板,一起剝皮案震驚了整個濱河市锥忿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怠肋,老刑警劉巖敬鬓,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異笙各,居然都是意外死亡钉答,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門杈抢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來数尿,“玉大人,你說我怎么就攤上這事惶楼∮冶模” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵鲫懒,是天一觀的道長嫩实。 經(jīng)常有香客問我刽辙,道長窥岩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任宰缤,我火速辦了婚禮颂翼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘慨灭。我一直安慰自己朦乏,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布氧骤。 她就那樣靜靜地躺著呻疹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪筹陵。 梳的紋絲不亂的頭發(fā)上刽锤,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音朦佩,去河邊找鬼并思。 笑死,一個胖子當(dāng)著我的面吹牛语稠,可吹牛的內(nèi)容都是我干的宋彼。 我是一名探鬼主播弄砍,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼输涕!你這毒婦竟也來了音婶?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤占贫,失蹤者是張志新(化名)和其女友劉穎桃熄,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體型奥,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡瞳收,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了厢汹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片螟深。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖烫葬,靈堂內(nèi)的尸體忽然破棺而出界弧,到底是詐尸還是另有隱情,我是刑警寧澤搭综,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布垢箕,位于F島的核電站,受9級特大地震影響兑巾,放射性物質(zhì)發(fā)生泄漏条获。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一蒋歌、第九天 我趴在偏房一處隱蔽的房頂上張望帅掘。 院中可真熱鬧,春花似錦堂油、人聲如沸修档。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吱窝。三九已至,卻和暖如春迫靖,著一層夾襖步出監(jiān)牢的瞬間院峡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工袜香, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撕予,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓蜈首,卻偏偏與公主長得像实抡,于是被迫代替她去往敵國和親欠母。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容