javaweb-----servlet開發

一、Servlet簡介

Servlet是sun公司提供的一門用於開發動態web資源的技術。
  Sun公司在其API中提供了一個servlet接口,用戶若想用發一個動態web資源(即開發一個Java程序向瀏覽器輸出數據),需要完成以下2個步驟:
  1、編寫一個Java類,實現servlet接口。
  2、把開發好的Java類部署到web服務器中。
  按照一種約定俗成的稱呼習慣,通常我們也把實現了servlet接口的java程序,稱之爲Servlet

二、Servlet的運行過程

Servlet程序是由WEB服務器調用,web服務器收到客戶端的Servlet訪問請求後:
  ①Web服務器首先檢查是否已經裝載並創建了該Servlet的實例對象。如果是,則直接執行第④步,否則,執行第②步。
  ②裝載並創建該Servlet的一個實例對象。
  ③調用Servlet實例對象的init()方法。
  ④創建一個用於封裝HTTP請求消息的HttpServletRequest對象和一個代表HTTP響應消息的HttpServletResponse對象,然後調用Servlet的service()方法並將請求和響應對象作爲參數傳遞進去。
  ⑤WEB應用程序被停止或重新啓動之前,Servlet引擎將卸載Servlet,並在卸載之前調用Servlet的destroy()方法。
  ### Servlet實現類

三、Servlet實現類

在這裏插入圖片描述

使用IDEA開發Servlet

在這裏插入圖片描述

Servlet映射路徑問題

1.一般情況下我們都會指定一個URL , 一個URL對應一個請求
2.通配問題
	/* :不報錯
	*.do

Reponse需要掌握

重定向

將這個請求,轉換到另一個地址;

比如,我們請求 : http://localhost:8080/servlet01/dasdasdasda/aaaa.do 他會跳轉到百度首頁;

//通過響應對象重定向頁面
resp.sendRedirect("404.jsp");

ServletContext

在這裏插入圖片描述

通過servletContext對象讀取網站配置文件

  1. 新建一個properties文件

    driver=com.mysql.jdbc.Driver
    username=root
    password=123456
    url=jdbc:mysql://localhost:3306/smbms
    
  2. 編寫servlet類

package com.wu.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

//讀取properties配置文件
public class ServletDemo03 extends HttpServlet {

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

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //讀取配置文件

    //1.獲得配置文件的路徑
    String realPath = this.getServletContext().getRealPath("/WEB-INF/classes/resources/database.properties");
    System.out.println("取得的路徑爲:"+realPath);

    Properties properties = new Properties();
    FileInputStream is = new FileInputStream(realPath);

    properties.load(is);//把文件流加載到配置文件的對象中;

    String driver = properties.getProperty("driver");
    String username = properties.getProperty("username");
    String password = properties.getProperty("password");
    String url = properties.getProperty("url");


    //響應到網頁
    resp.getWriter().println(driver);
    resp.getWriter().println(username);
    resp.getWriter().println(password);
    resp.getWriter().println(url);

    //=======================================
    System.out.println(driver);
    System.out.println(username);
    System.out.println(password);
    System.out.println(url);



}

}
3. 配置web.xml

<servlet>
    <servlet-name>Demo03</servlet-name>
    <servlet-class>com.kuang.servlet.ServletDemo03</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>Demo03</servlet-name>
    <url-pattern>/q3</url-pattern>
</servlet-mapping>
  1. 訪問查看

    localhost:8080/demo02/q3

  2. 項目結構

在這裏插入圖片描述

簡單驗證碼

package com.wu.servlet;




import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Map;

//驗證碼
public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //resp.getWriter().println(newRandom());

        //自動刷新網頁
        resp.setHeader("refresh","2");
        //驗證碼是一個圖片 , 我們需要製作一個圖片
        BufferedImage image = new BufferedImage(100,30,BufferedImage.TYPE_3BYTE_BGR);

        //圖片寫入一些東西
        Graphics2D graphics = image.createGraphics();
        graphics.setColor(Color.red);
        String num = String.valueOf(newRandom());
        graphics.drawString(num,10,10);

        //想辦法讓瀏覽器知道我們給的是一張圖片
        resp.setContentType("image/jpg");

        //讓網站去打開圖片
        ImageIO.write(image,"jpg",resp.getOutputStream());

    }


    //生成隨機數
    public int newRandom(){
        int num = (int)(Math.random()*9+1)*100000;
        return num;
    }

    /*
    @Test
public void  test(){

        ServletDemo04 servletDemo04 = new ServletDemo04();

        for (int j = 0; j < 100; j++) {
            int i = servletDemo04.newRandom();
            System.out.println(i);
        }
    }
    */  }

Servlet與普通Java類的區別

Servlet是一個供其他Java程序(Servlet引擎)調用的Java類,它不能獨立運行,它的運行完全由Servlet引擎來控制和調度。
  針對客戶端的多次Servlet請求,通常情況下,服務器只會創建一個Servlet實例對象,也就是說Servlet實例對象一旦創建,它就會駐留在內存中,爲後續的其它請求服務,直至web容器退出,servlet實例對象纔會銷燬。
  在Servlet的整個生命週期內,Servlet的init方法只被調用一次。而對一個Servlet的每次訪問請求都導致Servlet引擎調用一次servlet的service方法。對於每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,然後將這兩個對象作爲參數傳遞給它調用的Servlet的service()方法,service方法再根據請求方式分別調用doXXX方法。

如果在元素中配置了一個元素,那麼WEB應用程序在啓動時,就會裝載並創建Servlet的實例對象、以及調用Servlet實例對象的init()方法。

舉例:

 <servlet>
        <servlet-name>invoker</servlet-name>
        <servlet-class>
            org.apache.catalina.servlets.InvokerServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

用途:爲web應用寫一個InitServlet,這個servlet配置爲啓動時裝載,爲整個web應用創建必要的數據庫表和數據。

Servlet 的線程安全問題

當多個客戶端併發訪問同一個Servlet時,web服務器會爲每一個客戶端的訪問請求創建一個線程,並在這個線程上調用Servlet的service方法,因此service方法內如果訪問了同一個資源的話,就有可能引發線程安全問題。例如下面的代碼:

不存在線程安全問題的代碼:

 1 package wu.servlet;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 public class ServletDemo3 extends HttpServlet {
11 
12     
13     public void doGet(HttpServletRequest request, HttpServletResponse response)
14             throws ServletException, IOException {
15         
16         /**
17          * 當多線程併發訪問這個方法裏面的代碼時,會存在線程安全問題嗎
18          * i變量被多個線程併發訪問,但是沒有線程安全問題,因爲i是doGet方法裏面的局部變量,
19          * 當有多個線程併發訪問doGet方法時,每一個線程裏面都有自己的i變量,
20          * 各個線程操作的都是自己的i變量,所以不存在線程安全問題
21          * 多線程併發訪問某一個方法的時候,如果在方法內部定義了一些資源(變量,集合等)
22          * 那麼每一個線程都有這些東西,所以就不存在線程安全問題了
23          */
24         int i=1;
25         i++;
26         response.getWriter().write(i);
27     }
28 
29     public void doPost(HttpServletRequest request, HttpServletResponse response)
30             throws ServletException, IOException {
31         doGet(request, response);
32     }
33 
34 }

存在線程安全問題的代碼:

 1 package wu.servlet;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 public class ServletDemo3 extends HttpServlet {
11 
12     int i=1;
13     public void doGet(HttpServletRequest request, HttpServletResponse response)
14             throws ServletException, IOException {
15         
16         i++;
17         try {
18             Thread.sleep(1000*4);
19         } catch (InterruptedException e) {
20             e.printStackTrace();
21         }
22         response.getWriter().write(i+"");
23     }
24 
25     public void doPost(HttpServletRequest request, HttpServletResponse response)
26             throws ServletException, IOException {
27         doGet(request, response);
28     }
29 
30 }

把i定義成全局變量,當多個線程併發訪問變量i時,就會存在線程安全問題了,如下圖所示:同時開啓兩個瀏覽器模擬併發訪問同一個Servlet,本來正常來說,第一個瀏覽器應該看到2,而第二個瀏覽器應該看到3的,結果兩個瀏覽器都看到了3,這就不正常。
針對Servlet的線程安全問題,Sun公司是提供有解決方案的:讓Servlet去實現一個SingleThreadModel接口,如果某個Servlet實現了SingleThreadModel接口,那麼Servlet引擎將以單線程模式來調用其service方法。
  查看Sevlet的API可以看到,SingleThreadModel接口中沒有定義任何方法和常量,在Java中,把沒有定義任何方法和常量的接口稱之爲標記接口,經常看到的一個最典型的標記接口就是"Serializable",這個接口也是沒有定義任何方法和常量的,標記接口在Java中有什麼用呢?主要作用就是給某個對象打上一個標誌,告訴JVM,這個對象可以做什麼,比如實現了"Serializable"接口的類的對象就可以被序列化,還有一個"Cloneable"接口,這個也是一個標記接口,在默認情況下,Java中的對象是不允許被克隆的,就像現實生活中的人一樣,不允許克隆,但是隻要實現了"Cloneable"接口,那麼對象就可以被克隆了。

讓Servlet實現了SingleThreadModel接口,只要在Servlet類的定義中增加實現SingleThreadModel接口的聲明即可。
  對於實現了SingleThreadModel接口的Servlet,Servlet引擎仍然支持對該Servlet的多線程併發訪問,其採用的方式是產生多個Servlet實例對象,併發的每個線程分別調用一個獨立的Servlet實例對象。
  實現SingleThreadModel接口並不能真正解決Servlet的線程安全問題,因爲Servlet引擎會創建多個Servlet實例對象,而真正意義上解決多線程安全問題是指一個Servlet實例對象被多個線程同時調用的問題。事實上,在Servlet API 2.4中,已經將SingleThreadModel標記爲Deprecated(過時的)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章