1. 程式人生 > 實用技巧 >JSP原理和使用

JSP原理和使用

jsp簡介

JSP(全稱 Java Server Pages)Java 服務端頁面技術,是 JavaEE 平臺下的技術規範。它允許 使用特定的標籤在 HTML 網頁中插入 Java 程式碼,實現動態頁面處理,所以 JSP 就是 HTML 與 Java 程式碼的複合體。JSP 技術可以快速的實現一個頁面的開發,相比在 Servlet 中實現頁面開 發將變得更加容易。

jsp原理

jsp技術特點

  • JSP 和 Servlet 是本質相同的技術。當一個 JSP 檔案第一次被請求時,JSP 引擎會將該 JSP 編譯成一個 Servlet,並執行這個 Servlet。如果 JSP 檔案被修改了,那麼 JSP 引擎會重新編譯 這個 JSP。
  • JSP 引擎對 JSP 編譯時會生成兩個檔案分別是.java 的原始檔以及編譯後的.class 檔案,並 放到 Tomcat 的 work 目錄的 Catalina 對應的虛擬主機目錄中的 org\apache\jsp 目錄中。兩個 檔案的名稱會使用 JSP 的名稱加”_jsp”表示。如:index_jsp.java、index_jsp.class

jsp與servlet的區別

  • JSP以原始檔形式(副檔名以_jap.java和_jap.java結尾)部署到容器中。而 Servlet 需要編譯成 class 檔案後部署到容器中。
  • JSP 部署到 web 專案的根目錄下或根目錄下的其他子目錄和靜態同資源位於相同位置。而 Servlet 需要部署到 WEB-INF/classes 目錄中。
  • JSP 中的HTML程式碼會被 JSP 引擎放入到 Servlet 的 out.write()方法中。而在 Servlet 中我們需要自己通過對字元流輸出流的操作生成響應的頁面。
  • JSP 更擅長表現於頁面顯示(寫html程式碼),Servlet 更擅長於邏輯控制(寫java程式碼)

jsp使用

jsp三種原始標籤

jsp原始標籤再任何版本都能使用
<%! %> 宣告標籤

  • 宣告標籤用於在 JSP 中定義成員變數與方法的定義。標籤中的內容會出現在 JSP 被編譯 後的 Servlet 的 class 的{}中。

<% %> 指令碼標籤

  • 指令碼標籤用於在 JSP 中編寫業務邏輯。標籤中的內容會出現在 JSP 被編譯後的 Servlet的_jspService 方法體中。

<%= %> 賦值標籤

  • 賦值標籤用於在 JSP 中做內容輸出。標籤中的內容會出現在_jspService 方法的 out.print() 方法的引數中。注意我們在使用賦值標籤時不需要在程式碼中新增 ”;”。

jsp原始標籤使用
需求:以20%概率顯示你中獎了
首先idea匯入jar包是servlet—api,其次我們需要在web裡面建立.jsp檔案
jsp中不支援語句的巢狀

<%@ page import="java.util.Random" %><%--
  Created by IntelliJ IDEA.
  User: pain_
  Date: 2020/9/13
  Time: 10:49 下午
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
//    int flag =(int)(100*Math.random());
      int flag =new Random().nextInt(100);
    if(flag <= 20){

    %>
    中獎了<%=flag%>
    <%
        }else{
    %>
    再試試吧<%=flag%>
    <%
        }
    %>
</body>
</html>

常用的指令標籤分類

指令標籤作用宣告jsp頁面的一些屬性和動作
<%@指令名稱 屬性=“值” 屬性“值”%>
值是字串

  • page:主要宣告jsp頁面的一些屬性
    1.contextType 設定響應型別和編碼
    2.pageEncoding 設定頁面編碼
    3.import:匯入需要的包
    4.session:設定jsp頁面是否獲取session內建物件 (在宣告中可以設定是否獲取session屬性 session=“false”則不獲取。

  • include:靜態包含 可以將其他頁面內容包含進來,一起進行編譯執行,生成一個java.檔案
    <%@include file="包含jsp的相對路徑"%>

  • taglib;匯入標籤庫(匯入第三方標籤)
    <%taglib prefix="字首名“ url=”名稱空間“% >

jsp內建物件

  • request 物件
    request 物件是 HttpServletRequest 型別的物件。
  • response 物件
    response 物件是 HttpServletResponse 型別的物件。
  • session 物件
    session 物件是 HttpSession 型別的物件。只有在包含 session=“true” 的頁面中才可以被使用。
  • application 物件
    application 物件是 ServletContext 型別的物件
  • out 物件 字元輸出流
    out 物件是 JspWriter 型別的物件。
  • config 物件
    config 物件是 ServletConfig 型別的物件。
  • pageContext 物件
    pageContext 物件是 PageContext 型別的物件。作用是取得任何範圍的引數,通過 它可以獲取 JSP 頁面的 out、request、reponse、session、application 等物件。pageContext 物件的建立和初始化都是由容器來完成的,在 JSP 頁面中可以直接使用 pageContext 物件。
  • page 物件
    page 物件代表 JSP 本身。
  • exception 物件
    exception 物件的作用是顯示異常資訊,只有在包含 isErrorPage="true" 的頁面中才可以被使用。

請求轉發

什麼是請求轉發

請求轉發是服務端的一種請求方式,相當於在服務端中直接請求某個資源
request.getRequestDispatcher("該jsp的名稱.jsp").forword(request,response);

請求轉發和重定向的區別

  • 請求轉發對於客戶端瀏覽器而言是在一次請求與響應中完成,而重定向(需要客戶端發起)是在兩次請求兩次響應中完成。
  • 請求轉發並不會改變客戶端瀏覽器的位址列中的內容(在服務端直接完成)。而重定向會改變客戶端瀏覽器地
    址欄中的內容。
  • 請求轉發可以使用 request 物件傳遞資料,而重定向不能使用 request 物件傳遞資料(因為request是瀏覽器發出的請求,請求結束request生命週期結束了,再次請求則是新的request物件)。
  • 如果是處理的DML(新增修改刪除)操作,建議使用重定向方式為客戶端瀏覽器產生響應,可以解決表單重複提交現象。查詢使用請求轉發(請求轉發位址列不發生改變,因此提交資料表單

案例實現

  • servlet
/**
 * 需求:在 Servlet 中獲取客戶端瀏覽器所支援的語言,
 * 並通過 JSP 頁面將客戶端瀏覽器所支援的語言響應給客戶端瀏覽器。
 * */

//配置servlet註解與url對映
@WebServlet("/language.do")
public class LanguageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         String header =req.getHeader("Accept-language");
         req.setAttribute("key",header);
         req.getRequestDispatcher("/showMsg.jsp").forward(req,resp);
    }
}
  • jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
   <%
   String value =(String)request.getAttribute("key");
   %>
    當前支援的語言:<%=value
   %>
</body>
</html>
  • 結果

jsp四大作用域物件

作用域:資料共享的範圍,也就是說能夠在多大的範圍內郵箱

物件名稱 作用範圍
application(ServletContext) 整個應用都有效
session 在當前會話中有效
request 當前請求有效
paga(指jsp頁面本身) 當前頁面有效

JSTL標籤

JSTL(Java server pages standarded tag library,即 JSP 標準標籤庫)JSTL 標籤是基於 JSP 頁面的。這些標籤可以插入在 JSP 程式碼中,本質上 JSTL 也是提前定義好的一組標籤,這些標籤封裝了不同的功能,在頁面上呼叫標籤時,就等於呼叫了封裝起來的功能。JSTL 的目標是 使 JSP 頁面的可讀性更強、簡化 JSP 頁面的設計、實現了程式碼複用、提高效率。
在 JSP2.0 版本後開始支援 JSTL 標籤庫。在使用 JSTL 標籤庫時需要在 JSP 中新增對應的 taglib 指令標籤。

最常用的核心標籤

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
使用該標籤則需要進行相應的指令標籤

EL表示式

EL(Expression Language)是一種表示式語言。是為了使 JSP 寫起來更加簡單,減少 java 程式碼,可以使得獲取儲存在 Java 物件中的資料變得非常簡單。在 JSP2.0 版本後開始支援 EL 表示式。

語法結構

${表示式}
${物件.屬性名}

EL表示式中操作符

EL表示式的隱含物件

表示式去除作用域中的值

  • ${pageScope.name}
  • ${requestScope.name}
  • ${sessionScope.name}
  • ${applicationScope.name}
    獲取作用域屬性中的資料時,也可以只寫屬性名,EL 表示式會按照 pageScope、 requestScope、sessionScope、applicationScope 的順序查詢該屬性的值。${name}

JSTL標籤庫與表示式的使用

使用步驟

核心標籤的使用

可以結合EL表示式使用

  • <c:if>
    標籤判斷表示式的值,如果表示式的值為 true 則執行其主體內容。
  • <c:choose>, <c:when>, <c:otherwise>
    <c:choose>標籤與 Java switch 語句的功能一樣,用於在眾多選項中做出選擇。switch 語句中有 case,而<c:choose>標籤中對應有<c:when>,switch 語句中有 default, 而<c:choose>標籤中有<c:otherwise>。
    這三個標籤不能單獨出現
  • <c:forEach>

    迭代器,用於迭代集合。
    varStatus:屬性
    current: 當前這次迭代的(集合中的)項
    index: 當前這次迭代從 0 開始的迭代索引
    count: 當前這次迭代從 1 開始的迭代計數
    first: 用來表明當前這輪迭代是否為第一次迭代的標誌 返回布林型別
    last: 用來表明當前這輪迭代是否為最後一次迭代的標誌
    begin: 屬性值
    end: 屬性值
    step:屬性值
舉例
<%@ 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:if test="${1==1}">
       執行了
    </c:if>

    <c:choose>
        <c:when test="${2==1}">
            when執行了
        </c:when>
        <c:otherwise>
            otherwise執行了
        </c:otherwise>
    </c:choose>
    <hr/>
    <c:forEach begin="0" end="9" step="2" varStatus="a">
        ForEach...${a.count},${a.first},${a.last},${a.current}<br/>
    </c:forEach>
</body>
</html>

結果輸出

上面程式碼中當<c:when test="${2==1}">時,會輸出otherwise類似,java中的if.....else varStatus是迴圈狀態名稱.相應內容可以獲得迴圈的相應狀態

使用foreach案例

迭代List

建立 Users 物件,含有 userid,username 屬性。
建立一個 Servlet,在 Servlet 中建立多個 Users 物件並放到 List 集合中,在 showUsers.jsp
的頁面中顯示所有的 Users 物件的資訊。
建立User類

package pojo;

public class Users {
    private  Integer userId;
    private  String Username;

    public Users() {
    }

    public Users(Integer userId, String username) {
        this.userId = userId;
        Username = username;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUsername() {
        return Username;
    }

    public void setUsername(String username) {
        Username = username;
    }
}

建立Servlet

package com.hhxx.servlet;

import pojo.Users;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@WebServlet(urlPatterns = "/findUsers")
public class FindUsersServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Users> list =new ArrayList<>();
        Users users1 =new Users(1,"Lee");
        Users users2 =new Users(2,"Jay");
        list.add(users1);
        list.add(users2);
        //將屬性存放在req
        req.setAttribute("list",list);
        //跳轉的jsp位置
        req.getRequestDispatcher("showUsers.jsp").forward(req,resp);

    }
}

建立jsp(showUsers.jsp)

<%@ 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>
    <table border="1" align="center">
        <tr>
            <th>使用者ID</th>
            <th>使用者名稱</th>
        </tr>
        <c:forEach items="${requestScope.list}" var="a">
            <tr>
                <td>${a.userId}</td>
                <td>${a.username}</td>
            </tr>

        </c:forEach>
    </table>
</body>
</html>
  • 輸出結果
  • 通過請求定義的的值來傳遞屬性,JSP中var的迭代元素變數名稱可以隨便取,servlet要進行web配置,jsp也需要進行匯入標籤配置

迭代Map

  • uesrs類和上一致
  • 建立Servlet
package com.hhxx.servlet;

import pojo.Users;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@WebServlet(urlPatterns = "/findUsers2")
public class FindUsers2servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Map<String, Users> map = new HashMap<>();
        Users users1 =new Users(1,"Lee");
        Users users2 =new Users(2,"Jay");
        map.put("users1",users1);
        map.put("users2",users2);
        req.setAttribute("map",map);
        req.getRequestDispatcher("showUser2.jsp").forward(req,resp);
    }
}
  • 建立jsp
<%@ 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>
    <table border="2" >
        <tr>
            <td>Map的key</td>
            <td>使用者Id</td>
            <td>使用者名稱</td>
        </tr>

        <c:forEach items="${requestScope.map}" var="b">
         <tr>
            <td>${b.key}</td>
            <td>${b.value.userId}</td>
            <td>${b.value.username}</td>
        </tr>
        </c:forEach>
    </table>
</body>
</html>


與List相比不同之處在於:1.Map是無序的,2.Map是鍵-值(而我們目前的值包含2個userid,username)的資料,在jsp獲取時需要注意

格式化標籤使用

需配置檔案
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

案例對日期和數字的格式化處理

java

package com.hhxx.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

@WebServlet(urlPatterns = "/format")
public class FormatServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("date",new Date());
        req.setAttribute("balance",20210253.323);
        req.getRequestDispatcher("format.jsp").forward(req,resp);

    }
}

jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <fmt:formatDate value="${date}" pattern="yyyy-MM-dd"/>
    <fmt:formatNumber value="${requestScope.balance}" type="currency"/>
</body>
</html>
  • 結果

簡單理解MVC模式

什麼MVC

  • MVC 模式:Model、View、Controller 即模型、檢視、控制器。是軟體的一種架構模式 (Architecture pattern)。MVC 要實現的目標是將軟體的使用者介面和業務邏輯分離,可提高 程式碼可擴充套件性、可複用性、可維護性、以及靈活性。(不用元件做不同的事
    View(檢視):使用者的操作介面。如:html、jsp。 Model(模型):具體的業務模型與資料模型。如:service、dao、pojo。 Controller(控制):處理從檢視層傳送的請求,並選取模型層的業務模型完成響應的業務
    實現,併產生響應。如:Servlet。

MVC模式與應用程式分層的區別

MVC 模式是一種軟體的架構方式,而應用程式分層這是一種程式碼的組織方式。MVC 模式與應用程式分層的目標都是一致的:為了解耦和、提高程式碼複用性


最後這句話,讓我想起聽過的一本書說的,編寫程式碼的核心原則——ETC(容易變更)高內聚,低耦合 保證程式碼模組良好的設計,以及程式碼模組儘可能地複用,只需要一次修改,全部呼叫此模組的程式碼可以同步變更這裡MVC其實也是有這樣的一致認為。