JavaWeb筆記

一、Servlet
1、什麼是Servlet
Servlet是在服務器上運行的小程序,也就是一個Java類,Servlet是JavaWeb的三大組件之一(Servlet、Filter、Listener),它屬於動態資源。Servlet的作用是處理請求,服務器會把接收到的請求交給Servlet來處理,在Servlet中通常需要:
 接收請求數據;
 處理請求;
 完成響應。
例如客戶端發出登錄請求,或者輸出註冊請求,這些請求都應該由Servlet來完成處理。Servlet需要我們自己來編寫,每個Servlet必須實現javax.servlet.Servlet接口。Servlet對象駐留在服務器內存中。
2、Tomcat容器等級
Tomcat的容器分爲四個等級,Servlet的容器管理Context容器,一個Context對應一個Web工程。

3、實現Servlet的方式
實現Servlet有三種方式:
 實現javax.servlet.Servlet接口;
 繼承javax.servlet.GenericServlet類;
 繼承javax.servlet.http.HttpServlet類;
自定義Servlet類的繼承結構,如下圖:

3.1、實現Servlet接口的自定義Servlet
/**
* Servlet中的大部分方法(生命週期方法)都是有Tomcat服務器調用,
* Servlet對象也是由Tomcat服務器創建
*/
public class DemoServlet implements Servlet {

/*生命週期方法
* 在Servlet對象被銷燬前調用,並且只執行一次
* 一般用於釋放資源操作
*/
public void destroy() {
System.out.println(“destroy…..”);
}
/*用來獲取Servlet的配置信息
*/
public ServletConfig getServletConfig() {
System.out.println(“getServletConfig….”);
return null;
}
/* 獲取Servlet信息(一般無用)
*/
public String getServletInfo() {
System.out.println(“getServletInfo….”);
return null;
}
/*生命週期方法
* 在Servlet對象創建後立即執行,並且只執行一次
* 一般用於初始化操作
*/
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println(“init…..”);
}
/* 生命週期方法
* 每次處理請求都會執行該方法
*/
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
System.out.println(“service….”);
}
}
Servlet生命週期方法:
 void init(ServletConfig) 創建之後被調用(1次)
 void service(ServletRequest request,ServletResponse response)每次處理請求時被調用(多次)
 void destroy()銷燬之前被調用(1次)
特性:
 Servlet是單例的,一個類只有一個對象,可以存在多個Servlet類;
 線程不安全的,效率高;
 Servlet由我們自己編寫,對象由服務器來創建,由服務器調用相應方法。
3.2、實現第一個Servlet程序
1、重寫doGet()或doPost()方法
public class HelloServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    System.out.println("處理get請求。。。。");

//設置輸出格式和字符編碼
resp.setContentType(“text/html;charset=utf-8”);
//向頁面輸出內容
PrintWriter out = resp.getWriter();
out.println(“

Hello Servlet

“);
}

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

}

}
2、在web.xml中註冊Servlet

//url-pattern路徑前置的斜槓是代表當前項目

代碼示例:

HelloServlet
com.oracle.servlet.HelloServlet


HelloServlet
/servlet/HelloServlet

3、編輯JSP頁面
跳轉
//url路徑爲web.xml配置文件中rul-pattern標籤內容

4、執行結果

4、Servlet詳解
4.1、如何讓瀏覽器訪問Servlet
需要給Servlet指定一個路徑,讓Servlet與該路徑綁定在一起;
在瀏覽器中訪問該路徑;
這個路徑可以在web.xml中進行配置。

Demo
com.demo.DemoServlet


Demo
/demo.html

4.2、在web.xml配置初始化參數
web.xml

Demo
com.demo.DemoServlet

name
tom


password
1234


在Servlet中獲取參數和值
public void init(ServletConfig servletConfig) throws ServletException {
//方法一
String name = servletConfig.getInitParameter(“name”);
String pwd = servletConfig.getInitParameter(“password”);
System.out.println(name+”,”+pwd);

    //方法二
    Enumeration en = servletConfig.getInitParameterNames();
    while(en.hasMoreElements()){
        String key = (String) en.nextElement();
        String val = servletConfig.getInitParameter(key);
        System.out.println(key+","+val);
    }

}
4.3、GenericServlet概述
GenericServlet是Servlet接口的實現類(抽象類),我們可以通過GenericServlet來編寫自己的Servlet。
模擬GenericServlet類:
public class GServlet implements Servlet{

//聲明成員變量config
private ServletConfig config;

public void destroy() {
}

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

public String getServletInfo() {
    return null;
}

public void init(ServletConfig config) throws ServletException {
    this.config = config;
    init();//調用無參方法,方便子類的初始化操作
}

//聲明無參方法,方便子類中的初始化操作
public void init(){

}

public void service(ServletRequest request, ServletResponse response)
        throws ServletException, IOException {
}

public ServletContext getServletContext(){
    return config.getServletContext();
}

public String getServletName(){
    return config.getServletName();
}

public String getInitParameter(String name){
    return config.getInitParameter(name);
}

}
GServlet的子類:
public class SonGServlet extends GServlet {

@Override
public void init() {
    System.out.println("子類中的初始化操作");
}

@Override
public void service(ServletRequest request, ServletResponse response)
        throws ServletException, IOException {
    String name = getInitParameter("name");
    System.out.println(name);
}

}
4.4、HttpServlet概述
Tomcat調用service(ServletRequest,ServletResponse)方法,強轉兩個參數爲http協議相關的類型,然後再調用本類的service(HttpServletRequest,HttpServletResponse)。
該service()方法會通過request得到當前請求的請求方式,例如:GET或POST,根據請求的方式再調用doGet()或doPost()方法。doGet()和doPost()是由我們自己來覆蓋,如果沒有重寫doGet或doPost,並且他們被調用了,這時會出現405
演示:
在我們自定義的Servlet中,只重寫了doPost方法

在瀏覽器中發送GET請求,服務器會返回405,意思是不支持該請求方式

4.5、Servlet執行流程

4.6、Servlet生命週期

1)初始化階段,調用init()方法;
2)響應客戶請求階段,調用service()方法,由service()方法根據提交方式選擇執行doGet()或者doPost()方法;
3)終止階段,調用destroy()方法。
4.7、Tomcat裝載Servlet的三種情況
1)Servlet容器啓動時自動裝載某些Servlet,實現它只需要在web.xml文件中的之間添加如下代碼:1,數字越小表示優先級別越高。
2)在Servlet容器啓動後,客戶首次向Servlet發送請求。
3)Servlet類文件被更新後,重新裝載Servlet。
Servlet被裝載後,Servlet容器創建一個Servlet實例並且調用Servlet的init()方法進行初始化。在Servlet的整個生命週期內,init()方法只被調用一次。

5、Servlet與線程安全
因爲一個類型的Servlet只有一個實例對象,那麼就有可能會同時出現一個Servlet同時處理多個請求,那麼這樣Servlet就是線程不安全的,但是Servlet的工作效率很高。
解決方案:
 不要在Servlet中創建成員,創建局部變量即可;
 可以創建無狀態成員(無成員);
 可以創建有狀態成員,但狀態必須爲只讀的(只有getter方法);
6、讓服務器在啓動時就創建Servlet
默認情況下,服務器會在某個Servlet第一次收到請求時創建它,也可以在web.xml中對Servlet進行配置,使服務器啓動時就創建Servlet。
在標籤中,配置,其中給出一個非負整數,當有多個Servlet在服務器啓動時創建,那麼根據值的大小決定先後順序,小的在先。可以通過init()方法測試Servlet的創建時機。
在web.xml中配置

Demo
com.demo.DemoServlet
0


A
com.demo.HttpServletDemo
1

7、配置
是的子元素,用來指定Servlet的訪問路徑,即URL。它必須是以“/”開頭。
可以在中給出多個,例如:

DemoServlet
/AServlet
/BServlet

那麼這說明Servlet綁定兩個URL,無論訪問/AServlet還是/BServlet,訪問的都是DemoServlet。
還可以在中使用通配符,所謂通配符就是星號“*”,星號可以匹配任何URL前綴或後綴,使用通配符可以命名一個Servlet綁定一組URL,例如:
 /servlet/*:/servlet/a、/servlet/b,都匹配;
 *.do:/abc/def/ghi.do、/a.do,都可以匹配;
 /*:匹配所有URL
注意:通配符要麼爲前綴,要麼爲後綴,不能出現在URL中間位置,也不能只有通配符。例如:/.do就是錯誤的,因爲星號出現在URL的中間位置了。.*也是不對的,因爲一個URL最多只能有一個通配符。
通配符是一種模糊匹配URl的方式,如果存在更具體的,那麼訪問路徑會去匹配具體的。
8、設置初始化參數
在web.xml中配置Servlet時,可以配置一些初始化參數。而在Servlet中可以通過ServletConfig接口提供的方法來取得這些參數。
在web.xml配置文件中初始化參數信息

HelloServlet
com.oracle.servlet.HelloServlet

username
admin


pwd
1234



HelloServlet
/servlet/HelloServlet

在Servlet類中的init()方法內接收初始化信息
public class HelloServlet extends HttpServlet {
private String username;
private String pwd;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    resp.setContentType("text/html;charset=utf-8");
    PrintWriter out = resp.getWriter();
    out.println("<h2>"+getUsername()+"</h2>");
    out.println("<h2>"+getPwd()+"</h2>");
}

@Override                                                                    
public void init() throws ServletException {                                 
    this.setUsername(this.getInitParameter("username"));                         
    this.setPwd(this.getInitParameter("pwd"));                             
}

}

前端訪問效果

9、web.xml文件的繼承
每個完整的JavaWeb應用中都需要有web.xml,在
$[CATALINA_HOME]\conf\web.xml中的內容,相當於寫到了每個項目的web.xml中,它是所有web.xml的父文件。
10、ServletContext概述
一個項目只有一個ServletContext對象,服務器會爲每個應用創建一個ServletContext對象,我們可以在N多個Servlet中來獲取這個唯一的對象,使用它可以給多個Servlet傳遞數據,與Tomcat同生同死。
 ServletContext對象的創建是在服務器啓動時完成的;
 ServletContext對象的銷燬是在服務器關閉時完成的。
ServletContext對象的作用是在整個Web應用的動態資源直接共享數據。例如在AServlet中向ServletContext對象中保存一個值,然後在BServlet中就可以獲取這個值,這就是數據共享。
獲取ServletContext
在Servlet中獲取ServletContext對象:
 在void init(ServletConfig config)中:
ServletContext context = config.getServletContext();
public class DemoServlet implements Servlet {
public void init(ServletConfig config) throws ServletException {
ServletContext context = config.getServletContext();
}
}
 在GenericServlet或HttpServlet中獲取ServletContext對象:
GenericServlet類有getServletContext()方法,所以可以直接使用this.getServletContext()類獲取。
public class HttpServletDemo extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
}
}
 HttpSession中也可以通過getServletContext()方法來獲得
11、域對象的功能
ServletContext是JavaWeb四大域對象之一:
 PageContext
 ServletRequest
 HttpSession
 ServletContext
所有域對象都是有存取數據的功能,因爲域對象內部有一個Map,用來存儲數據,下面是ServletContext對象用來操作數據的方法:
 void setAttribute(String name,Object val):用來存儲一個對象,也可以成爲存儲一個域,參數分別爲域的屬性名和屬性值,如果多次調用該方法,並且使用相同的name,那麼就會覆蓋上一次的值,這一特性與Map相似。
 Object getAttribute(String name):用來獲取ServletContext中的數據,當前在獲取之前需要先存儲。
 void removeAttribute(String name):用來移除ServletContext中的域屬性,如果參數name不存在,那麼該方法什麼都不做。
 Enumeration getAttributeNames():獲取所有域屬性的名稱。
12、獲取應用初始化參數
Servlet也可以獲取初始化參數,但它是局部的參數,即一個Servlet只能獲取自己的初始化參數,不能獲取別人的。可以設置公共的初始化參數,爲所有Servlet而用,這需要使用ServletContext才能使用。
web.xml文件配置

context_name
123


AServlet
com.demo.AServlet


AServlet
/AServlet

在AServlet類中獲取參數
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = getServletContext();
String name = context.getInitParameter(“context_name”);
System.out.println(name);
}
}

13、獲取資源相關方法

public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

    //獲取帶有盤符的路徑
    String path = this.getServletContext().getRealPath("/a.txt");

    //獲取資源路徑後,再獲取輸入流對象
    InputStream is = this.getServletContext().getResourceAsStream("/a.txt");

    //獲取當前路徑下的所有資源路徑
    Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF");

}

}
14、練習:統計網站訪問量
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

    /*
     * 獲取ServletContext對象,並從該對象中獲取名爲“count”的屬性
     * 第一次訪問時,該屬性不存在,就創建該屬性
     * 以後每次訪問,對該屬性的值做累加
     */
    ServletContext app = this.getServletContext();
    Integer count =  (Integer) app.getAttribute("count");
    if(count == null){
        count=1;
        app.setAttribute("count", count);
    }else{
        app.setAttribute("count", ++count);
    }

    //向頁面輸出內容
    //設置服務器響應的格式和編碼
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    out.println("<h1>您當前是第<font color=\'red\'>" + count +
            "</font>位訪問者</h1>");

}

}
15、獲取類路徑下資源
類路徑對一個JavaWeb項目而言,就是/WEB-INF/classes和/WEB-INF/lib/每個jar包。
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

    /*
     * 先得到Class,在得到ClassLoader
     * 得到的是當前項目下的a.txt
     */
    ClassLoader cl = this.getClass().getClassLoader();
    InputStream is = cl.getResourceAsStream("a.txt");
    //把資源文件放到與當前類同目錄下的訪問路徑
    InputStream is2 = cl.getResourceAsStream("com/demo/a.txt");
    //相對.class文件所在目錄
    Class c = this.getClass();
    InputStream in = c.getResourceAsStream("a.txt");
    //相對於classes
    c.getResourceAsStream("/a.txt");
    //獲取index.jsp資源
    c.getResourceAsStream("/../../index.jsp");

    //使用Struts的commons-io-xx.jar
    String s = IOUtils.toString(is);
    System.out.println(s);
}

}

16、MVC架構
16.1、什麼是MVC模式
MVC是一種目前廣泛流行的軟件設計模式,它把應用程序分爲三個核心模塊:模型(Model)、視圖(View)、控制器(Controller),它們各自處理自己的任務。旨在分離模型、控制、視圖。是一種分層思想的體現。
模型(Model)代表應用程序的數據和用於控制、訪問和修改這些數據的業務規則;
視圖(View)用來組織模型的內容,它從模型那裏獲得數據,並指定這些數據如何表現;
控制器(Controller)定義了應用程序的行爲,它負責對來自視圖的用戶要求進行解釋,並把這些要求映射成相應的行爲,這些行爲由模型負責實現。
16.2、MVC的處理過程
1)瀏覽器發送一次請求,被控制器(Controller)接收,在Java Web開發中,充當控制器角色的就是Servlet
2)由Servlet實例化一個模型層的對象,通常使用Javabean來充當模型層,由Javabean去調用數據庫並獲得數據,再返回給控制層,同時也可以被視圖層直接訪問
3)控制層獲得模型層返回的數據,再將數據傳給視圖層,通常使用jsp充當視圖層

模型2

二、請求和響應機制
1、服務器處理請求的流程
服務器每次收到請求時,都會爲這個請求開闢一個新的線程。服務器會把客戶端的請求數據封裝到request對象中,request就是請求數據的載體。服務器還會創建response對象,這個對象與客戶端連接在一起,它可以用來向客戶端發送響應。
2、HttpServletResponse對象
ServletResponse是與協議無關的類型,HttpServletResponse與http協議相關的類型。
2.1、狀態碼
200表示成功、302表示重定向、404表示客戶端錯誤(訪問的資源不存在)、500表示服務器端錯誤
方法:
 sendError(int sc)
 sendError(int sc,String msg)
 setStatus(int sc)
實例:發送404
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendError(404, “訪問到了,但是不讓你看!!!”);
}
}
2.2、響應頭
Content-Type、Refresh、Location等等
頭就是一個鍵值對,可能會存在一個頭一個值,也可能會存在一個頭多個值。
方法:
 setHeader(String name,String val):適用於單值的響應頭
例如:response.setHeader(“name”, “tom”);
 addHeader(String name,String val):適用於多值的響應頭
例如:
response.addHeader(“aa”, “A”);
response.addHeader(“aa”, “B”);
……
 setIntHeader(String name,int val):適用於單值的int類型的響應頭
//一般用戶返回請求內容長度
response.setIntHeader(“Content-Length”, 1024);
 addIntHeader(String name,int val):適用於多值的int類型的響應頭
 setDateHeader(String name,long val):適用於單值的毫秒類型的響應頭
 addDateHeader(String name,long val):適用於多值的毫秒類型的響應頭
實例:
發送302,設置Location頭,完成重定向
public class BServlet extends HttpServlet {

/**
 * 瀏覽器請求當前Servlet,重定向到CServlet
 */
public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("BServlet...");
    //向客戶端響應頭信息
    response.setHeader("Location", "/hello/CServlet");
    response.sendError(302);
}

}
設置Refresh,定時刷新
public class BServlet extends HttpServlet {

/**
 * 瀏覽器請求當前Servlet,重定向到CServlet
 */
public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    System.out.println("BServlet...");
    //向客戶端響應頭信息
    response.setContentType("text/html;charset=utf-8");
    PrintWriter pw =  response.getWriter();
    pw.println("頁面將在5秒之後跳轉!");

    response.setHeader("Refresh", "5;URL=/hello/CServlet");
}

}
禁用瀏覽器緩存:Cache-Control、pragma、expires
public class BServlet extends HttpServlet {

/**
 * 設置瀏覽器禁用緩存
 */
public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("pragma", "no-cache");
    response.setDateHeader("expires", -1);  
}

}
標籤可以代替響應頭:

2.3、響應體
通常是html,也可以是圖片。
response的兩個流:
 ServletOutputStream,用來向客戶端發送字節數據
 PrintWriter,用來向客戶端發送字符數據,需要設置編碼
兩個流不同同時使用
實例:
使用PrintWriter發送字符數據
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//設置輸出格式和編碼
response.setContentType(“text/html;charset=utf-8”);
//使用字符流響應
PrintWriter out = response.getWriter();
out.println(“

Hello World

“);
}
使用ServletOutputStream發送字節數據(圖片)
public class BServlet extends HttpServlet {
/** 響應字節數據
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path = “D:\psb.jpg”;
FileInputStream fis = new FileInputStream(path);
//使用commons-io.jar包的類
byte[] bytes = IOUtils.toByteArray(fis);
response.getOutputStream().write(bytes);
}
}
2.4、重定向
設置302,設置Location,其中變化的只有Location,所以java提供了一個快捷方法,完成重定向。
sendRedirect(String location)方法
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect(“/hello/CServlet”);
}
3、HttpServletRequest對象
request對象封裝了客戶端所有的請求數據。
3.1、獲取常用信息
 String getRemoteAddr():獲取客戶端IP
 String getMethod():獲取請求方式
3.2、獲取HTTP請求頭
 String getHeader(String name):適用於單值頭
 int getIntHeader(String name):適用於單值int類型的請求頭
 long getDateHeader(String name):適用於單值毫秒類型的請求頭
 Enumeration getHeaders(String name):適用於多值請求頭
實例:
通過User-Agent識別用戶瀏覽器類型
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//獲取客戶端IP
String addr = request.getRemoteAddr();
System.out.println(“IP:”+addr);
//獲取客戶端請求方式
String method = request.getMethod();
System.out.println(“請求方式:”+method);
//獲取User-Agent的請求頭
String userAgent = request.getHeader(“User-Agent”);
System.out.println(userAgent);
}
3.3、獲取請求URL
例如:http://localhost:8080/hello/AServlet?name=tom&pwd=123
 String getScheme():獲取協議,http
 String getServerName():獲取服務器名,localhost
 String getServerPort():獲取服務器端口,8080
 String getContextPath():獲取項目名,/hello
 String getServletPath():獲取Servlet路徑,/AServlet
 String getQueryString():獲取參數部分,問號後面的,name=tom&pwd=123
 String getRequestURI():獲取請求URI,等於項目名+Servlet路徑,
/hello/AServlet
 String getRequestURL():獲取請求URL,等於不包含參數的整個請求路徑
http://localhost:8080/hello/AServlet
實例:
防盜鏈,如果請求不是通過本站的超鏈接發出來的,發送錯誤狀態碼404,Referer這個請求頭,表示請求的來源。
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//獲得訪問來源
String path = request.getHeader(“Referer”);
if(path == null || !path.contains(“localhost”)){
response.sendError(404,”您不是通過正常網站訪問該頁面”);
}else{
response.getWriter().println(“hello world”);
}
}
3.4、獲取請求參數
請求參數是由客戶端發送給服務器,有可能是在請求體重(POST),也可能是在URL之後(GET)。請求參數有一個參數一個值的,也有一個參數多個值的,例如複選框。
 String getParameter(String name):獲取指定名稱的請求參數值,適用於單值請求參數
 String[] getParameterValues(String name):獲取指定名稱的請求參數值,適用於多值請求參數
 Enumeration getParameterNames():獲取所有請求參數名稱
 Map

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