天天看點

Java學習路線-48:Servlet學習

課時1 Servlet是什麼

Servlet作用是處理請求

接收請求

處理請求

完成響應

課時2 實作Servlet方式

依賴

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>      

實作方式

// 實作接口:
javax.servlet.Servlet

// 繼承類:
javax.servlet.GenericServlet

// 繼承類:
javax.servlet.HttpServlet      

繼承示例

AServlet.java

import javax.servlet.*;
import java.io.IOException;

public class AServlet implements Servlet{

    // 建立時執行
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    // 擷取配置資訊
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    // 處理請求
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    // 擷取servlet資訊
    @Override
    public String getServletInfo() {
        return null;
    }

    // 銷毀前調用
    @Override
    public void destroy() {

    }
}
      

課時3 Servlet的生命周期

生命周期

init    執行個體化調用
service 每次處理請求都調用
destroy 銷毀調用      

特性

(1)單例,每個類隻有一個對象

(2)線程不安全,效率最高

Servlet類由使用者自定義,對象由伺服器來建立,并有伺服器調用對應的方法

浏覽器通路Servlet

給Servlet配置一個路徑

web.xml

<?xml version="1.0" encoding="utf-8" ?>

<web-app>
    <!-- 注冊 Servlet,幫助web伺服器反射該類 -->
    <servlet>
        <servlet-name>demo</servlet-name>
        <servlet-class>AServlet</servlet-class>
    </servlet>
    
    <!-- 映射 Servlet 資源,用url-pattern元素标示 URL -->
    <servlet-mapping>
        <servlet-name>demo</servlet-name>
        <url-pattern>demo</url-pattern>
    </servlet-mapping>
</web-app>      

目錄結構

webapp
    └── WEB-INF
        ├── classes
        │   └── AServlet.class
        └── web.xml      

課時4 ServletConfig介紹

interface ServletConfig{
    // 擷取servlet-name中的内容
    String getServletName() 

    // 擷取Servlet上下文對象
    ServletContext getServletContext() 

    // 擷取指定初始化參數值
    String getInitParameter(String name) 

    // 擷取所有初始化參數值
    Enumeration<String> getInitParameterNames() 

}      
<servlet> 
    <init-param>
        <param-name>name</param-name>
        <param-value>Tom</param-value>
    </init-param>
</servlet>      

擷取參數

@Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println(servletConfig.getInitParameter("name"));
    }
@Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println(servletConfig.getInitParameter("name"));
    }      

課時5 ServletRequest和Servletresponse對象

interface ServletRequest;

interface ServletResponse;      

課時6 GenericServlet介紹

GenericServlet可以隻覆寫service方法,不用全寫

基本原理

import javax.servlet.*;
import java.io.IOException;

public class AServlet implements Servlet {
    private ServletConfig config = null;

    @Override
    public void init(ServletConfig servletConfig) {
        this.config = servletConfig;
        this.init();
    }

    // 實作此方法,初始化後可以調用
    public void init() {

    }

    @Override
    public ServletConfig getServletConfig() {
        return this.config;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
      

使用示例

import javax.servlet.*;
import java.io.IOException;

public class AServlet extends GenericServlet {

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        servletResponse.getWriter().write("<h2>hello<h2>");
    }
}      

課時7 HttpServlet介紹

源碼

package javax.servlet.http;


public abstract class HttpServlet extends GenericServlet {
    // 重寫
    protected void doGet(HttpServletRequest req, HttpServletResponse resp);
    
    // 重寫
    protected void doPost(HttpServletRequest req, HttpServletResponse resp);

    protected void service(HttpServletRequest req, HttpServletResponse resp);

    public void service(ServletRequest req, ServletResponse res){
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            HttpServletRequest request = (HttpServletRequest)req;
            HttpServletResponse response = (HttpServletResponse)res;
            this.service(request, response);
        } else {
            throw new ServletException("non-HTTP request or response");
        }
    }
}
      

使用示例: 接收GET請求

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("<h2>hello</h2>");
    }
}
      

課時8 Servlet的細節

1、非線程安全

一個Servlet類隻有一個執行個體對象,不是線程安全的,工作效率高

(1)不要在Servlet中建立成員,建立局部變量即可

(2)可以建立無狀态成員

(3)可以建立有狀态的成員,但是狀态必須為隻讀

2、建立時啟動

預設情況下,伺服器會在第一次通路Servlet時建立執行個體對象

給load-on-startup設定一個非負整數

正數的值越小,啟動該servlet的優先級越高

可以配置建立時啟動

<servlet>
    <servlet-name>servletName</servlet-name>
    <load-on-startup>0</load-on-startup>
</servlet>      

3、url-pattern

可以有多個通路路徑

可以使用字首或者字尾通配符

*

<servlet>
    <servlet-name>servletName</servlet-name>
    <!-- 字尾比對 -->
    <url-pattern>/demo/*</url-pattern>
    <!-- 字首比對 -->
    <url-pattern>*.do</url-pattern>
    <!-- 比對所有url -->
    <url-pattern>/*</url-pattern>
</servlet>      

課時9 在conf下的web.xml檔案内容介紹

${CATALINA_HOME}/conf/web.xml

<!-- 優先級最低 -->
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!-- 過期時間30分鐘 -->
<session-config>
    <session-timeout>30</session-timeout>
</session-config>

<!-- 類型映射 -->
<mime-mapping>
    <extension>xml</extension>
    <mime-type>application/xml</mime-type>
</mime-mapping>      

課時10 Servlet與反射

Servlet通過反射,擷取配置檔案的類名,進行執行個體化和方法調用

課時11 ServletContext概述

一個項目隻有一個ServletContext對象

可以在多個Servlet中傳遞對象

Tomcat啟動時建立,關閉時銷毀

課時12 擷取ServletContext對象

擷取ServletContext

class ServeletConfig{
    ServletContext getServletContext();
}

class GenericServlet{
    ServletContext getServletContext();
}
      

課時13 示範ServletContext

域對象: 在多個Servlet中傳遞資料

class ServletContext{
    // 設定 多次調用會覆寫
    void setAttribute(String name, Object vlaue);
    // 擷取
    Object getAttribute(String name);
    // 移除
    void removeAttribute(String name);
    // 擷取全部屬性名稱
    Enumeration getAttributeNames();
}
      

例如: AServlet的資料可以傳遞到BServlet

package com.pengshiyu;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String name = request.getParameter("name");
        ServletContext context = getServletContext();
        context.setAttribute("name", name);
        response.getWriter().write("<h2>" + name +"</h2>");
    }

}
      
package com.pengshiyu;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServletContext context = getServletContext();
        String name = (String)context.getAttribute("name");
        response.getWriter().println(name);
    }
}
      

課時14 ServletContext擷取公共的初始化參數

Servlet隻能擷取自己的初始化參數

ServletContext擷取公共的初始化參數

<web-app>
    <context-param>
        <param-name>key</param-name>
        <param-value>value</param-value>
    </context-param>
</web-app>      
package com.pengshiyu;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServletContext context = getServletContext();
        String name = context.getInitParameter("key");
        response.getWriter().println(name);
    }
}
      

課時15 ServletContext擷取資源相關方法

以webapp文根目錄

ServletContext context = getServletContext();

// 擷取絕對路徑
String path = context.getRealPath("/index.html");

// 擷取檔案後轉為輸入流
InputStream in = context.getResourceAsStream("/index.html");

// 擷取目錄下的檔案
Set<String> set = context.getResourcePaths("/");
// [/hello.html, /WEB-INF/]      

課時16 網站通路量統計小案例

使用ServletContext對象共享統計資料

package com.pengshiyu;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ServletContext context = getServletContext();
        Integer count = (Integer) context.getAttribute("count");

        if (count == null) {
            count = 1; // 第一次通路
        } else {
            count++;
        }

        response.setContentType("text/html; charset=UTF-8");
        response.getWriter().println("<h2>第"+count+"次通路</h2>");
        context.setAttribute("count", count);
    }
}      

課時17 擷取類路徑下的資源

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>      

代碼執行個體

package com.pengshiyu;

import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

public class Demo {

    public static void main(String[] args) throws IOException {

        Class<Demo> clazz = Demo.class;

        // 1、相對于.class所在目錄
        InputStream input1 = clazz.getResourceAsStream("1.txt");
        System.out.println(IOUtils.toString(input1, StandardCharsets.UTF_8));

        // 2、相對于/classes
        InputStream input2 = clazz.getResourceAsStream("/2.txt");
        System.out.println(IOUtils.toString(input2, StandardCharsets.UTF_8));

        ClassLoader loader = clazz.getClassLoader();

        // 3、相對于/classes
        InputStream input3 = loader.getResourceAsStream("3.txt");
        System.out.println(IOUtils.toString(input3, StandardCharsets.UTF_8));

    }
}
      

課時18 BaseServlet

一個Servlet中可以有多個請求處理方法

BaseServlet.java

package com.pengshiyu;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String methodName = req.getParameter("method");

        if(methodName == null || methodName.trim().isEmpty()){
            throw new RuntimeException("method is null or empty");
        }
        System.out.println(methodName);

        // 通過參數擷取方法
        Class clazz = this.getClass();

        Method method = null;
        try {
            method = clazz.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException("方法擷取失敗");
        }

        // 調用方法
        try {
            method.invoke(this, req, resp);
        } catch (Exception e) {
            throw new RuntimeException("調用失敗");
        }

    }
}
      
package com.pengshiyu;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class AServlet extends BaseServlet {

    public void getAge(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.getWriter().print("getAge");
    }

    public void getName(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.getWriter().print("getName");
    }

}
      

調用時傳入查詢參數

http://localhost:8080/demo/hello?method=getAge