1. 程式人生 > >Servlet開發

Servlet開發

driver 用戶 調度員 init方法 靜態 技術 use ins 只需要

自MVC規範出現後,Servlet的責任開始明確下來,僅僅作為控制器使用,不再需要生成頁面標簽,也不再做為視圖層角色使用。servlet通常被稱為服務器端小程序,是運行在服務器端的程序 。用於處理用戶的請求及響應。

一. Servlet 介紹

Servlet是特殊的Java類,這個Java類必須繼承HTTPServlet,每個servlet可以響應用戶的請求。Servlet提供不同的方法用於相應用戶的請求

  • doGet():用於相應客戶端的get請求
  • doPost():用於響應客戶端的Post請求
  • doPut():用於相應客戶端的put請求
  • doDelete():用於相應客戶端的delete請求

事實上,客戶端請求通常只有get和post兩種,servlet為了響應這兩種請求,必須重寫doPost()和doGet()兩個方法。

大部分時候,servlet對於所有請求的響應都是都是完全一樣的。因此可以采用重寫一個方法來代替上面四個方法:只需要重寫service方法即可響應客戶端所有請求。

另外,HTTPServlet還包括另外兩個方法

  • init(ServletConfig config):創建servlet實例時,使用該方法初始化Servlet資源。
  • destroy():銷毀Servlet實例時,自動調用該方法回收資源

通常無需重寫這兩個方法。除非需要初始化Servlet時,完成某些資源初始化的方法,才考慮重寫init()方法。如果需要在銷毀Servlet之前,先完成某些資源的回收,比如關閉數據庫連接等,才需要重寫destroy方法。

Servlet與JSP的區別在於:

  • Servlet沒有內置對象,原JSP中的內置對象必須由程序顯示創建
  • 對於靜態的HTML標簽,servlet必須使用頁面輸出流逐行輸出

二. Servlet 配置

編輯好的servlet源文件並不能響應用戶請求,還必須將其編譯成class文件 。將編譯後的class文件放在WEB-INF/classes路徑下,如果servlet有包,則還應該將class文件放在對應的包路徑下。

為了讓Servlet響應用戶請求,還必須將Servlet配置在web應用中。配置Servlet時,需要修改web.xml文件》

從servlet3.0開始,配置servlet的兩種方式

  • 在servlet類中使用@webServlet註解進行配置
  • 通過在web.xml文件中進行配置

使用註解@webServlet配置Servlet時,常用的屬性有

@webServlet支持的常用屬性
屬性 是否必須 說明
asynsSupported 指定該Servlet是否支持異步操作模式
displayName

指定該Servlet的顯示名

initParam 用於為該Servlet配置參數
loadOnStartup 用於將該servlet配置成load-on-startup 的 Servlet
name 指定該servlet的名字
urlPatterns/value 都指定servlet處理的URL

如果打算使用註解來配置Servlet,有兩點需要指出:

  • 不要在web.xml文件的根元素(<web-app.../>)中指定metadata-complete="true".
  • 不要在web.xml文件中配置該servlet。

如果打算使用web.xml文件來配置該Servlet,則需要配置如下兩個部分。

  • 配置Servlet的名字:對應web.xml文件中的<servlet/>元素
  • 配置servlet的URL,對應web.xml文件中的<servlet-mapping/>元素。這一步是可選的。但如果沒有為Servlet配置URL,則該servlet不能響應該用戶請求。

三. JSP/Servlet 的生命周期

當Servlet在容器中運行時,其實例的創建及銷毀等都不是程序員決定的,而是由web容器進行控制的的

創建servlet實例有兩個時機

  • 客戶端第一次請求某個Servlet時,系統創建該Servlet的實例:大部分的Servlet都是這種Servlet
  • Web應用啟動時立即創建Servlet實例,即load-on-startup Servlet.

每個Servlet運行都遵循如下生命周期

  1. 創建Servlet實例
  2. Web容器調用Servlet的init方法,對Servlet進行初始化。
  3. Servlet初始化後,將一直保存在容器中,用於響應客戶端的請求,調用doGet()或者doPost()方法處理並響應請求,或者統一使用service方法
  4. web容器決定銷毀Servlet時,先調用Servlet的destroy()方法,通常在關閉Web應用時銷毀Servlet。

四. load-on-startup Servlet

應用啟動時就創建的Servlet通常是用於某些後臺服務的Servlet,或者攔截很多請求的Servlet,這種Servlet通常作為應用的基礎Servlet使用,提供重要的後臺服務。

配置load-on-startup的Servlet有兩種方式

  • 在web.xml文件中通過<servlet.../>的子元素<load-on-startup.../>進行配置
  • 通過@webServlet註解的loadOnStartup屬性指定

<load-on-startup.../>元素和loadOnStartup屬性都只接受一個整型值,這個整型值越小,Servlet越優先實例化

五. 訪問servlet的配置參數

配置Servlet時,還可以增加額外的配置參數。通過使用配置參數,可以實現提供更好的可移植性,避免將參數以硬代碼的方式寫在代碼程序中。

設置參數的兩種方式

  • 通常@webServlet 的initParam屬性來指定
  • 通過在web.xml文件的<servlet.../>元素中添加<init-param.../>指定

訪問Servlet參數通過servletConfig對象完成,ServletConfig提供如下方法。

String getInitParamter(String name):用於獲取初始化參數

六. 使用Servlet作為控制器

在標準的Java EE的MVC設計模式中Servlet僅作為控制器使用。JSP作為表現層技術,其作用有兩點

  • 負責收集用戶請求參數
  • 將應用的處理結果,狀態數據呈現給用戶

servlet僅充當控制器角色,它的作用類似於調度員;所有用戶請求都發給Servlet,Servlet調用Model來處理用戶請求,並調用JSP來呈現處理結果;或者Servlet直接調用JSP將應用的狀態數據呈現給用戶

model通常由JavaBean充當,所有業務邏輯,數據訪問邏輯都在model中實現。事實上,隱藏在Model下的可能還有很多豐富的組件,例如dao組件,領域對象等,下面介紹了一個使用Servlet作為控制器的MVC應用,該應用演示了一個簡單的登錄驗證。

<%@ page contentType="text/html;charset=UTF-8" language="java"  errorPage="" %>
<html>
<head>
    <title>new document</title>
</head>
<body>
<span style="color:red;font-weight: bold;">
    <%
    if(request.getAttribute("err") != null){
        out.println(request.getAttribute("err")+"<br/>");
    }
    %>
</span>
請輸入用戶名和密碼:<br/>
<form id="login" method="post" action="login">
    用戶名: <input type="text" name="username"><br/>&nbsp;&nbsp;碼:<input type="password" name="pass"/><br/>
    <input type="submit" value="登錄">
</form>
</body>
</html>
package java.gdut.servlet;

import javax.servlet.RequestDispatcher;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.sql.ResultSet;

@WebServlet(name = "login",urlPatterns = "/login")
public class LoginServlet extends javax.servlet.http.HttpServlet {
    protected void service(javax.servlet.http.HttpServletRequest request,
                           javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
        String errMsg = "";
        RequestDispatcher rd;
        String username = request.getParameter("username");
        String pass = request.getParameter("pass");
        try{
            DbDao db = new DbDao("jdbc:mysql://localhost:3306/tb_test","com.mysql.jdbc.Driver","sherman","a123");
            ResultSet rs = db.querry("select pass from user_inf where name=?",username);
            if(rs.next()){
                if(rs.getString("pass").equals(pass)){
                    HttpSession session = request.getSession(true);
                    session.setAttribute("name",username);
                    rd=request.getRequestDispatcher("/welcome.jsp");
                    rd.forward(request,response);
                }else{
                    errMsg+="您的用戶密碼不符合,請重新輸入";
                }
            }else{
                errMsg+="您的用戶名不存在,請先註冊";
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        if(errMsg != null && !errMsg.equals("")){
            rd = request.getRequestDispatcher("/login.jsp");
            request.setAttribute("err",errMsg);
            rd.forward(request,response);
        }
    }


}
package java.gdut.servlet;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class DbDao {
    private Connection conn;
    private String url;
    private String driver;
    private String user;
    private String pass;

    public DbDao(String url, String driver, String user, String pass) {
        this.url = url;
        this.driver = driver;
        this.user = user;
        this.pass = pass;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getPass() {
        return pass;
    }

    public void setPass(String pass) {
        this.pass = pass;
    }

    /**
     * 獲取數據庫連接
     */
    public Connection getConn() throws Exception {
        if (conn == null) {
            Class.forName(this.driver);
            conn = DriverManager.getConnection(this.url, this.user, this.pass);
            System.out.println(conn);
        }
        return conn;
    }

    /**
     * 執行插入
     * @param sql
     * @param args
     * @return
     * @throws Exception
     */
    public boolean insert(String sql,Object... args) throws Exception{
        PreparedStatement prst = getConn().prepareStatement(sql);
        for (int i = 0; i <args.length ; i++) {
            prst.setObject(i+1,args[i]);
        }
        if(prst.executeUpdate() != 1){
            return false;
        }

        return true;
    }

    /**
     * 執行查詢
     * @param sql
     * @param args
     * @return
     * @throws Exception
     */
    public ResultSet querry(String sql,Object... args)throws Exception{
        PreparedStatement prst = getConn().prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            prst.setObject(i+1,args[1]);
        }
        return prst.executeQuery();
    }

    public void modify(String sql,Object... args)throws Exception{
        PreparedStatement prst = getConn().prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            prst.setObject(i+1,args[1]);
        }
        prst.executeUpdate();
        prst.close();
    }

    public void closeConn()throws Exception{
        if(null != conn && !conn.isClosed()){
            conn.close();
        }
    }


}

Servlet開發