Servlet & JSP & Filter & Listener

Servlet & JSP & Filter & Listener

graph TB B[Servlet] C[JSP] B --> D[基本原理與執行流程<br>init/service/do.] B --> H[service&反射] B --> I[單例] C --> E[隱式對象] C --> F[JSTL&EL] C --> G[session<br>JavaBean]

Servlet

Servlet 是運行在服務器端的一個對象,web 服務器(如 Tomcat)會根據用戶的訪問連接將請求路由到不一樣的 Servlet 中並由其處理與返回響應。路由配置通常在 web.xml 中,固然也可使用註解的形式。javascript

特色

  • 單例
  • Servlet 在請求時實例化與初始化,web 服務建立時默認不建立 Servlet 對象,不過能夠配置自啓動(load-on-startup

基本原理

下面是 HTML & servlet & web.xml 的一個示例css

HTML(注意 action 和 method 的取值):html

...
<form action="login" method="post">
帳號: <input type="text" name="name"> <br>
密碼: <input type="password" name="password"> <br>
<input type="submit" value="登陸">
</form>
...

web.xml(注意 Servlet 和 url 路徑的映射關係):前端

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>LoginServlet</servlet-class>
        <load-on-startup>10</load-on-startup> 
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>  
</web-app>

Servlet:java

public class LoginServlet extends HttpServlet{
    // @Override // 當前函數的做用見下
    // public void service(HttpServletRequest request, HttpServletResponse response){...}
    // public void init(ServletConfig config) {...} // 繼承於父類,Servlet 的構造函數執行後會自動執行此函數,只會執行一次
 	// 處理 GET 請求
    public void doGet(HttpServletRequest request, HttpServletResponse response){
        try {
            response.getWriter().println("<h1>Hello Servlet!</h1>");
            response.getWriter().println(new Date().toLocaleString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 處理 POST 請求
    public void doPost(HttpServletRequest request, HttpServletResponse response){
        try{
            String name = request.getParameter("name");
        	String password = request.getParameter("password");
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

每個 Servlet 都須要繼承 HttpServlet。HttpServlet 中有一個 service 成員函數,默認的 service 會判斷請求中的方法,並根據方法(GET or POST)來調用當前函數下的 doGet 或者 doPost 方法。結合 Filter(見下文) & 重寫service & 反射能夠實現一個 servlet 處理不一樣的請求,以下所示:web

使用 Filter 拆分用戶的請求,下面代碼截取自一段 Filter 對象:瀏覽器

// 假設請求的方法是 ***/admin_category_list
if(uri.startsWith("/admin_")){		
	String servletPath = StringUtils.substringBetween(uri,"_", "_") + "Servlet"; // 肯定 Servlet
	String method = StringUtils.substringAfterLast(uri,"_" );
	request.setAttribute("method", method); // 肯定方法
	req.getRequestDispatcher("/" + servletPath).forward(request, response); // 執行 Servlet
	return;
}

重寫 service 函數並使用反射選擇與執行 Servlet 中的方法(此時 Servlet 中能夠沒有 doGet 和 doPost):tomcat

@Override
public void service(HttpServletRequest request, HttpServletResponse response) {
    ...
    try {
        /*藉助反射,調用對應的方法*/
        String method = (String) request.getAttribute("method");
        Method m = this.getClass().getMethod(method, javax.servlet.http.HttpServletRequest.class,
                                             javax.servlet.http.HttpServletResponse.class,Page.class);
        String redirect = m.invoke(this,request, response,page).toString();
    }
    ...
}

常見方法

  • 跳轉
    • 服務端跳轉(返回跳轉頁的響應內容但不改變瀏覽器地址):request.getRequestDispatcher("success.html").forward(request, response);
    • 客戶端跳轉(服務端向客戶端發送重定向地址):response.sendRedirect("fail.html");
  • Servlet 自啓動
    • 在 web.xml 中配置 <load-on-startup>10</load-on-startup> ,能夠實現 Servlet 的自啓動

JSP

JSP(Java Server Pages),一個混合 Java&HTML 的網頁編寫技術。JSP 最終將會被翻譯爲 Servlet 。JSP 繼承於 HttpJspBase,然後者繼承自 HttpServlet。服務器

JSP 示例

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
<%
    List<String> words = new ArrayList<String>();
    words.add("today");
    words.add("is");
    words.add("great");
%>
<table width="200px" align="center" border="1" cellspacing="0">
<%for (String word : words) {%>
<tr>
    <td><%=word%></td>
</tr>
<%}%>
</table>

網頁中輸出以下:session

today
is
great

JSP 組成

JSP 由這些頁面元素組成:

  1. 靜態內容,html、css、javascript 等內容
  2. 指令,以<%@開始 %> 結尾,好比 <%@page import="java.util.*"%>
  3. 表達式 <%=%>,用於輸出一段html,<%="hello jsp"%> 相似於 <%out.println("hello jsp");%>
  4. Scriptlet,在 <%%> 之間,能夠寫任何 java 代碼
  5. 聲明,在<%!%> 之間能夠聲明字段或者方法。可是不建議這麼作。
  6. 動做,<jsp:include page="Filename" >jsp 頁面中包含另外一個頁面。
  7. 註釋 <%-- -- %>,不一樣於 html 的註釋<!-- --> 經過 jsp 的註釋,瀏覽器也看不到相應的代碼,至關於在servlet中註釋掉了

隱式對象

不須要顯式定義就可使用的對象。JSP 一共有 9 個隱式對象,分別爲:

  • request、response、out,out 爲輸出
  • pageContext、session、application,分別表明當前頁,會話,全局做用域對象
  • JSP 會被編譯爲一個 Servlet 類 ,運行的時候是一個 Servlet 實例。 page 即表明 this
  • config,config 能夠獲取一些在 web.xml 中初始化的參數
  • exception,異常對象,指定的異常處理頁面纔可以使用

JSTL

JSTL(JSP Standard Tag Library),JSTL容許開人員能夠像使用 HTML 標籤那樣在 JSP 中開發 Java 功能。

常見函數標籤:fmt、fn

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%-- 指明後續的標籤使用都會以<c: 開頭 --%>

<c:set var="name" value="${'gareen'}" scope="request" />
經過標籤獲取name: <c:out value="${name}" /> <br> <%-- 相似<%=request.getAttribute("name")%> --%>

<c:remove var="name" scope="request" /> <br>
經過標籤獲取name: <c:out value="${name}" /> <br>

<c:set var="hp" value="${3}" scope="request" /> <%-- 循環示例 --%>
<c:choose>
    <c:when test="${hp<5}">
        <p>這個英雄要掛了</p>
    </c:when>
    <c:otherwise>
        <p>這個英雄以爲本身還能夠再搶救搶救</p>
    </c:otherwise>
</c:choose>

EL 表達式

EL表達式能夠從 pageContext、request、session、application四個做用域中取到值,若是 4 個做用域都有相同屬性,EL會按照從高到低的優先級順序獲取:pageContext > request > session > application

JSP 常見用法

  • include
    • 指令 include:<%@include file="footer.jsp" %>,當前 JSP 將插入到命令行位置
    • 動做 include:<jsp:include page="footer.jsp" />,footer.jsp 會被轉化未 footer_jsp.java 以 Servlet 的形式存在,footer_jsp.java 的執行結果會插入到命令位置
  • 跳轉
    • 客戶端跳轉:<%response.sendRedirect("hello.jsp");%>
    • 服務端跳轉:<jsp:forward page = "hello.jsp"/>

JavaBean

JavaBean 的標準

  1. 提供無參 public 的構造方法(默認提供)
  2. 每一個屬性,都有 public 的 getter 和 setter
  3. 若是屬性是 boolean,那麼就對應 is 和 setter 方法

Session

Session 就是是會話。會話指的是從用戶打開瀏覽器訪問一個網站開始,不管在這個網站中訪問了多少頁面,點擊了多少連接,都屬於同一個會話,直到該用戶關閉瀏覽器爲止。

Servlet + JSP ≈ MVC

Servlet 方便寫 Java 代碼,JSP 方便寫頁面代碼,結合兩者的特色,使用 Servlet 寫業務相關代碼,使用 JSP 進行展現。

Servlet,將數據保存到隱式對象

public class HeroEditServlet extends HttpServlet {
 
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        int id = Integer.parseInt(request.getParameter("id"));
        Hero hero = new HeroDAO().get(id);
        request.setAttribute("hero", hero); // 設置屬性後 JSP 使用 EL 語言 ${hero.id},得到數據
        request.getRequestDispatcher("editHero.jsp").forward(request, response);
    }
}

JSP,從隱式對象中得到數據

<form action='updateHero' method='post'>
    名字 : <input type='text' name='name' value='${hero.name}'> <br>
    血量 :<input type='text' name='hp' value='${hero.hp}'> <br>
    傷害: <input type='text' name='damage' value='${hero.damage}'> <br>
    <input type='hidden' name='id' value='${hero.id}'>
    <input type='submit' value='更新'>
</form>

應用舉例

  • 使用分頁技術顯示部分數據
    • 後臺返回在指定範圍內的數據,前端顯示

Filter

Filter 就像一個一個哨卡,用戶的請求須要通過 Filter,能夠設置多個 Filter

graph LR A[用戶訪問] A --> B((Filter 1)) B --> C((Filter 2)) C --> D((Filter ..)) D --> E[Servlet]

示例

web.xml 配置

<filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>filter.FirstFilter</filter-class>
</filter>
 
<filter-mapping>
    <filter-name>FirstFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Filter

public class FirstFilter implements Filter {
    @Override
    public void destroy() { }
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
 		...
        chain.doFilter(request, response);
    }
 
    @Override
    public void init(FilterConfig arg0) throws ServletException {
 	// Filter必定會隨着 tomcat 的啓動自啓動,故 init 隨着 tomcat 啓動時執行
    }
}

Listener

Listener 用於監聽 web 應用的建立與銷燬、全局屬性的變化、Session和Request對象的聲明週期。

繼承 ServletContextListener 對象並實現其中兩個方法的對象能夠實現對 web 建立與銷燬的監聽,每當 web 應用重啓或者銷燬,系統會自動調用對應的函數。

繼承 ContextAttributeListener 並實現其中函數,能夠在全局屬性發生變化時(增、刪、改等)執行指定函數。

一樣的,能夠編寫 Listener 實現 Session&Request 對象的生命週期和屬性變化的監控。

舉個例子,經過記錄 Session 的個數能夠實如今線用戶的計算。以一種簡單的方式,經過編寫 Listener 來監控 Session 的建立與銷燬並在對應時刻修改全局計數器的值,這樣就能夠實如今線用戶的統計了。可參考

相關文章
相關標籤/搜索