1. 程式人生 > 實用技巧 >servlet核心技術2

servlet核心技術2

一、Servet 與 JDBC

  • Servlet中可以使用JDBC技術訪問資料庫,查詢DB資料,然後生成顯示頁面,接收請求引數,然後對DB操作
  • 為了方便重用和便於維護等目的,經常會採用DAOData Access Object)模式對資料庫操作進行獨立封裝。

package com.utils;

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

public class Dbutils {
    private   static  String dbNAME;
    private   static  String dbURL;
    private   static  String dbUSERNAME;
    private   static  String dbPASSWORD;
    static {
        dbNAME="com.mysql.jdbc.Driver";
        dbURL="jdbc:mysql://127.0.0.1:3306/db_web?characterEncoding=utf-8";
        dbUSERNAME="root";
        dbPASSWORD="123456";
        try {
            Class.forName(dbNAME);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        Connection con= DriverManager.getConnection(dbURL,dbUSERNAME,dbPASSWORD);
        return con;
    }

    public static void close(Connection con) throws SQLException {
        if (con!=null){
            con.close();
        }
    }

    public static void close(Connection con, PreparedStatement ps) throws SQLException {
        if (null!=ps){
            ps.close();
        }
        close(con);

    }
}
package com.dao;

import com.modal.User;
import com.utils.Dbutils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class UserDao {
    public int creatUser(User user){
        Connection con=null;
        PreparedStatement ps=null;
        try {
            con= Dbutils.getConnection();
            String sql="insert into User values(null,?,?)";
            ps= con.prepareStatement(sql);
            ps.setString(1,user.getUserName());
            ps.setString(2,user.getPassword());
            //資料庫原表ALTER TABLE USER MODIFY userName VARCHAR(20) CHARACTER SET "utf8";不然無法識別中文
            int row = ps.executeUpdate();
            return  row;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                Dbutils.close(con,ps);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return 0;
    }
}
package com.servlet;

import com.dao.UserDao;
import com.modal.User;

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;

@WebServlet(name = "RegisterServlet")
public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        String name = request.getParameter("userName");
        String password = request.getParameter("password");
        System.out.println("使用者名稱:"+name+",密碼:"+password);
        User user = new User(name, password);
        UserDao userDao = new UserDao();
        int i = userDao.creatUser(user);
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        if(i==1) {
            writer.write("<h1>註冊成功</h1>");
        }else{
            writer.write("<h1>註冊失敗</h1>");
        }
        writer.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

二、重定向與轉發

1.重定向

  • 客戶瀏覽器傳送http請求,當web伺服器接受後傳送302狀態碼響應及對應新的location給客戶瀏覽器,客戶瀏覽器發現是302響應,則自動再發送一個新的http請求,
  • 請求url是新的location地址,伺服器根據此請求尋找資源併發送給客戶
  • 藉助javax.servlet.http.HttpServletResponse介面void sendRedirect(String location)
  • 特點:重定向之後,瀏覽器位址列的URL會發生改變;重定向過程中會將前面Request物件銷燬,然後建立一個新的Request物件;重定向的URL可以是其它專案工程

package com;

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;

@WebServlet(name = "RedirectServlet")
public class RedirectServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("開始重定向");
        response.sendRedirect("https://www.jiegeng.com/bz=18052915230356");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊登入頁面</title>
</head>
<body>
    <form action="redirect" method="post">
        重定向頁面 <br>
    <input type="submit" value="提交"></form>

</body>
</html>

2.轉發

  • 一個Web元件(Servlet/JSP)將未完成的處理通過容器轉交給另外一個Web元件繼續處理,轉發的各個元件會共享RequestResponse物件。
方法宣告 功能介紹
Object getAttribute(String
name)
將指定屬性值作為物件返回,若給定名稱屬性不存
在,則返回空值
void setAttribute(String
name,Object o)
在此請求中儲存屬性值

方法宣告 功能介紹
RequestDispatcher
getRequestDispatcher(String path)
返回一個RequestDispatcher物件,該物件充當位
於給定路徑上的資源的包裝器

方法宣告 功能介紹
void forward(ServletRequest
request, ServletResponse response)
將請求從一個servlet轉發到伺服器上的另一個資
源(ServletJSP檔案或HTML檔案)
  • 特點:轉發之後瀏覽器位址列的URL不會發生改變;轉發過程中共享Request物件;轉發的URL不可以是其它專案工程。

  

package com;

import javax.servlet.RequestDispatcher;
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;

@WebServlet(name = "ForwardServlet")
public class ForwardServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("開始轉發");
        request.setAttribute("key1","value1");
        RequestDispatcher requestDispatcher = request.getRequestDispatcher("forwardEnd");
        requestDispatcher.forward(request,response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}
//--------------------------
package com;

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;

@WebServlet(name = "ForwardEndServelet")
public class ForwardEndServelet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("轉發成功");
        System.out.println(request.getAttribute("key1"));
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>註冊登入頁面</title>
</head>
<body>
    <form action="forward" method="post">
        轉發頁面 <br>
    <input type="submit" value="提交"></form>

</body>
</html>

3.重定向與轉發的區別

  • 請求次數:重定向是瀏覽器向伺服器傳送一個請求並收到響應後再次向一個新地址發出請求,轉發是通過容器轉交給另外一個Web元件繼續處理,伺服器收到請求後為了完成響應跳轉到一個新的地址;重定向至少請求兩次,轉發請求一次
  • 位址列不同:重定向位址列會發生變化,轉發位址列不會發生變化;
  • 是否共享資料:重定向兩次請求不共享資料,轉發一次請求共享資料(在request級別使用資訊共享,使用重定向必然出錯);
  • 跳轉限制:重定向可以跳轉到任意URL,轉發只能跳轉本站點資源
  • 發生行為不同:重定向是客戶端行為,重定向可以轉到不同伺服器的專案中,轉發是伺服器端行為,只能在本站目錄下的專案被使用;
  • Request物件:重定向過程中會將前面Request物件銷燬,然後建立一個新的Request物件,而轉發是共享Request物件

三、Servlet執行緒安全

  • 伺服器在收到請求之後,會啟動一個執行緒來進行相應的請求處理。
  • 預設情況下,伺服器為每個Servlet只建立一個物件例項。當多個請求訪問同一個Servlet時,會有多個執行緒訪問同一個Servlet物件,此時就可能發生執行緒安全問題。
  • 多執行緒併發邏輯,需要使用synchronized對程式碼加鎖處理,但儘量避免使用
package com;

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;

@WebServlet(name = "ThreadServlet",urlPatterns = "/thread")
public class ThreadServlet extends HttpServlet {
    private String name;
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        synchronized (this) {
            System.out.println("執行緒測試");
            //1.獲取名字
            name=request.getParameter("name");
            System.out.println(name);
            //2.啟動執行緒睡眠
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //3.輸出姓名
        PrintWriter writer = response.getWriter();
        writer.write("<h1>"+name+"</h1>");
        writer.close();

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request,response);
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>thread測試</title>
</head>
<body>

<iframe width="300px" height="100px" src="thread?name=admin1"></iframe>
    <iframe width="300px" height="100px" src="thread?name=admin2"></iframe>
    <iframe width="300px" height="100px" src="thread?name=admin3"></iframe>

</body>
</html>

四. 狀態管理

  • Web程式基於HTTP協議通訊,而HTTP協議是無狀態的協議,一旦伺服器響應完客戶的請求之後,就斷開連線,而同一個客戶的下一次請求又會重新建立網路連線。
  • 把瀏覽器與伺服器之間多次互動作為一個整體,將多次互動所涉及的資料儲存下來,即狀態管理。
  • 多次互動的資料狀態可以在客戶端儲存,也可以在伺服器端儲存。狀態管理主要分為以下兩類:
    • 客戶端管理:將狀態儲存在客戶端。基於Cookie技術實現。
    • 伺服器管理:將狀態儲存在伺服器端。基於Session技術實現。

1.cookie技術

    • cookie表示客戶端以-形式進行儲存的一種技術。
    • 瀏覽器向伺服器傳送請求時,伺服器將資料以Set-Cookie訊息頭的方式響應給瀏覽器,瀏覽器會將這些資料以文字檔案的方式儲存起來。
    • 當瀏覽器再次訪問伺服器時,會將這些資料以Cookie訊息頭的方式傳送給伺服器
    • 使用javax.servlet.http.Cookie類的構造方法實現Cookie的建立。
      方法宣告 功能介紹
      void addCookie(Cookie cookie) 新增引數指定的物件到響應
    • 使用javax.servlet.http.HttpServletResponse介面的成員方法實現Cookie的新增。
      方法宣告 功能介紹
      Cookie[] getCookies() 返回此請求中包含的所有Cookie物件
    • 使用javax.servlet.http.HttpServletRequest介面的成員方法實現Cookie物件的獲取。
      方法宣告 功能介紹
      String getName() 返回此Cookie物件中的名字
      String getValue() 返回此Cookie物件的數值
      void setValue(String newValue) 設定Cookie的數值