1. 程式人生 > >java學習day32---servlet(上)

java學習day32---servlet(上)

Servlet 
是伺服器端執行的java小程式,起到一個橋樑的作用,用於瀏覽器和應用程式之間進行溝通。

1. tomcat 的目錄結構

    bin  可執行指令碼目錄
    conf 配置檔案目錄
    logs 日誌目錄
    webapps  應用程式目錄
    
2. 啟動和停止
前提條件:安裝JDK並配置JAVA_HOME環境

啟動: bin/startup.bat (windows下)
停止: bin/shutdown.bat (windows下)   或者   在啟動的cmd黑視窗下 CTRL+C (停止程式,不是拷貝)

可以用瀏覽器檢查它是否真正啟動: 在瀏覽器位址列輸入 http://localhost:8080      
                                                    http://127.0.0.1:8080
                                                    http://192.168.10.240:8080
                                                    當埠號為80時可以省略不寫

3.在IDEA中設定Tomcat

File---New---Project---Java Enterprise---選擇Project SDK,JavaEE version---選擇JBoss中的Web Application---起名建立成功---Run---Edit Configration...選擇Tomcat Servlet,然後啟動,如果自動跳轉一個$Title$頁面則為啟動成功

4. 修改埠號

在conf/server.xml 檔案中搜索8080 找到後修改為其它埠號即可

5. 編寫第一個servlet
 * 1. 建立一個類繼承 HttpServlet父類
 * 2. 使用註解 @WebServlet(urlPatterns = "/瀏覽器訪問路徑"),記得要有斜槓
 * 3. 重寫父類中  service 方法

@WebServlet(urlPatterns = "/hello")   //注意:在一個專案內,多個servlet的urlPatterns不能重複,要確保唯一
public class MyServlet extends HttpServlet {

    @Override
    // Request : 代表請求
    // Response : 代表響應
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("你好,世界");

        resp.setContentType("text/html;charset=utf-8");  // 對於中文,需要設定響應採用utf-8字符集,否則會有亂碼問題

        // 向resp物件物件的字元輸出流中寫入的html程式碼都會返回給瀏覽器
        resp.getWriter().println("<html><body>你好,世界</body></html>");
    }
}

6. 瀏覽器傳送請求

語法:
http://ip地址:埠號/servlet地址?引數名1=引數值1&引數名2=引數值2...
       
例如:  ?name=張三&pass=123  // name是引數名,張三是引數值, pass是引數名, 123 是引數值

伺服器要獲取請求引數:
String 請求引數的值 = request.getParameter("請求引數名");

注意:
    如果某個引數沒有傳遞,使用request.getParameter()返回的是null值
    request.getParameter()返回的總是字串,需要自己做資料型別轉換

package web;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * 1. 繼承 HttpServlet父類
 * 2. 使用註解 @WebServlet(urlPatterns = "瀏覽器訪問路徑")
 * 3. 覆蓋父類中  service 方法
 */
@WebServlet(urlPatterns = "/hello")
public class MyServlet extends HttpServlet {

    @Override
    // Request : 代表請求
    // Response : 代表響應
    // %E4%B8%AD 中  %E6%96%87 文
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 手工進行解碼, 需要放在所有 req.getParameter方法之前呼叫
        req.setCharacterEncoding("utf-8");

        // 用req可以獲取瀏覽器發過來的請求引數
        System.out.println(req.getParameter("name")); // 根據名稱獲取值
        System.out.println(req.getParameter("pass"));

        System.out.println("你好,世界");
        // 用servlet可以返回一段html程式碼,給瀏覽器

        // 對於中文,需要設定響應採用utf-8字符集,否則會使用英文字符集(iso-8859-1)返回響應,會有亂碼問題
        resp.setContentType("text/html;charset=utf-8");

        // 向resp物件物件的字元輸出流中寫入的html程式碼都會返回給瀏覽器
        // 希望返回伺服器的時間
        resp.getWriter().println("<html><body>你好,世界,現在時間是:" + new Date() + "</body></html>");
    }
}

7. 請求型別

在HTML程式碼中,method後面跟的引數就是請求型別,不寫則預設為get請求
get 和 post(預設請求時get)

兩者的區別:

        1) get請求會把所有請求引數跟在位址列之後,不適合傳送敏感資訊
            而post請求不會把請求引數跟在位址列之後
        2) 不要以為post請求是安全的,通過一些網路監測工具仍然可以看到post中的引數資訊
            http 是不安全的,都是明文傳送給伺服器的
            https 是安全的,會把資訊傳送給伺服器的過程中進行加密
            https 和post結合可以保證向伺服器傳輸資料的安全性
        3) get請求傳輸的資料有限制, post請求沒有限制(任意大小的資料都可以傳送給伺服器)
        4) get 意味著獲取資訊(對應查詢操作)
           post 意味著增,改,刪等操作
        5) 對於post請求,會有中文亂碼問題,

            要在 req.getParameter方法之前呼叫req.setCharacterEncoding("utf-8");進行手工解碼

預設請求引數(get)

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

@WebServlet(urlPatterns = "/ReqParaTest")
public class ReqParaTest extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("這是關於請求引數的測試");
        System.out.println(req.getParameter("name")); //根據name引數得到對應的引數值
        System.out.println(req.getParameter("pass")); //根據pass引數得到對應的引數值
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().println("<html><body>hello,world 現在時間" +new Date() + "</body></html>");
    }
}

執行結果:根據網址中輸入的引數值列印到控制檯上

當請求引數是get時,會將一些敏感資訊直接暴露在位址列上,不安全,例子如下

請求引數的java程式碼同上,HTML程式碼如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="ReqParaTest" method="get">  <!--action後面跟的引數即為對應的Servlet程式碼,如果method不出現,則預設也是get請求-->
    <input type="text" name="name">
    <input type="submit" value="提交">
</form>
</body>
</html>

在位址列輸入HTML程式碼的地址

提交之後執行結果:會發現位址列上有輸入的使用者名稱及密碼資訊

而如果請求是post,則只會在列印臺輸出,而不會顯示在位址列上

執行結果:

> 注意: tomcat 8 已經對get請求中的中文按utf-8進行解碼了, 所以程式設計師不需要對get請求的中文進行額外處理
         tomcat 7, tomcat 6 ... 對get請求中的中文還需要特殊處理

8.servlet 的生命週期

瀏覽器首次向此servlet傳送請求時,會建立它的例項物件;以後再發送請求使用的仍然是第一次建立的物件。
結論:整個生命週期中,servlet只有一個例項(單例的)

1) 構造方法首先執行(只執行一次)
2) 初始化方法init (只執行一次)
3) 服務方法 service (反覆被執行)來一次請求執行一次
4) 銷燬方法 destroy (只執行一次)在伺服器停止前,或重新部署時

import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

import java.io.IOException;

@WebServlet(urlPatterns = "/live")
public class ServletLive extends HttpServlet {
    public ServletLive() {
        System.out.println("Servlet構造方法執行");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("Servlet初始化方法執行");
    }

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("Servlet的服務方法執行");
    }

    @Override
    public void destroy() {
        System.out.println("Servlet銷燬方法執行");
    }
}

開啟頁面localhost:8080/live,會發現構造方法,初始化方法,服務方法都被執行,但是不斷重新整理這個頁面,只會不斷執行服務方法,當停止伺服器時,執行銷燬方法

9.關於資料的頁面展示

一個java web專案:
|-
    |-WEB-INF (受保護不能直接訪問)
        |-classes 放自己編寫的java類
        |-lib    放第三方的jar包
    |-css 放樣式表
    |-js  放js指令碼
    |-jsp 放網頁檔案
    |-index.jsp 首頁面 如果沒有寫具體的地址,會按 index.html, index.jsp

10.用servlet對資料庫中的資料進行操作

如以資料庫中的student為例,顯示student這張表格

import util.Utils;   //這是JDBC中方便之後呼叫的工具類包,可以參考之前的程式碼

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;

@WebServlet(urlPatterns = "/OutputStuServletTest")  
public class OutputStuServletTest extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.println("<html><body><table border = ''><tbody>");
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection conn = null;
            PreparedStatement stmt = null;
            ResultSet rs = null;
            try {
                conn = Utils.getConnection();
                stmt = conn.prepareStatement("select * from student");
                rs = stmt.executeQuery();
                while(rs.next()) {
                    int sid = rs.getInt("sid");
                    String sname = rs.getString("sname");
                    String birthday = rs.getString("birthday");
                    String sex = rs.getString("sex");
                    System.out.println(sid + "---" + sname + "---" + birthday + "---" + sex);
                    out.println(
                            "<tr><td>"+sid+"</td><td>"+sname+"</td><td>"+sname+"</td><td>"+sname+"</td></tr>"
                            //sid + "---" + sname + "---" + birthday + "---" + sex + "<br>"
                    );
                }
                out.println("</tbody></table></body></html>");
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                Utils.close(rs, stmt, conn);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

執行結果: