HTTP:
- 概念:Hyper Text Transfer Protocol 超文本傳輸協定
- 傳輸協定:定義了,用戶端和伺服器端通信時,發送資料的格式
- 特點:
- 基于TCP/IP的進階協定
- 預設端口号:80
- 基于請求/響應模型的:一次請求對應一次響應
- 無狀态的:每次請求之間互相獨立,不能互動資料
- 曆史版本:
- 1.0:每一次請求響應都會建立新的連接配接
- 1.1:複用連接配接
- 請求消息資料格式
-
請求行
請求方式 請求url 請求協定/版本
GET /login.html HTTP/1.1
- 請求方式:
- HTTP協定有7中請求方式,常用的有2種
- GET:
- 請求參數在請求行中,在url後。
- 請求的url長度有限制的
- 不太安全
- POST:
- 請求參數在請求體中
- 請求的url長度沒有限制的
- 相對安全
- GET:
- HTTP協定有7中請求方式,常用的有2種
- 請求方式:
-
請求頭:用戶端浏覽器告訴伺服器一些資訊
請求頭名稱: 請求頭值
* 常見的請求頭:
1. User-Agent:浏覽器告訴伺服器,我通路你使用的浏覽器版本資訊
* 可以在伺服器端擷取該頭的資訊,解決浏覽器的相容性問題
2. Referer:http://localhost/login.html * 告訴伺服器,我(目前請求)從哪裡來? * 作用: 1. 防盜鍊: 2. 統計工作:
-
請求空行
空行,就是用于分割POST請求的請求頭,和請求體的。
- 請求體(正文):
- 封裝POST請求消息的請求參數的
- 字元串格式:
POST /login.html HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0 Accept: text/html,application/xhtml+xml,application/xml; q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5, en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Referer: http://localhost/login.html Connection: keep-alive Upgrade-Insecure-Requests: 1 username=zhangsan
-
Request:
- request對象和response對象的原理
- request和response對象是由伺服器建立的。我們來使用它們
- request對象是來擷取請求消息,response對象是來設定響應消息
-
request對象繼承體系結構:
ServletRequest -- 接口
| 繼承
HttpServletRequest -- 接口
| 實作
org.apache.catalina.connector.RequestFacade 類(tomcat)
- request功能:
- 擷取請求消息資料
- 擷取請求行資料
- GET /day14/demo1?name=zhangsan HTTP/1.1
- 方法:
- 擷取請求方式 :GET
- String getMethod()
- 擷取虛拟目錄:/day14
- String getContextPath()
- 擷取Servlet路徑: /demo1
- String getServletPath()
- 擷取get方式請求參數:name=zhangsan
- String getQueryString()
- 擷取請求URI:/day14/demo1
- String getRequestURI():傳回/day14/demo1
- StringBuffer getRequestURL():傳回http://localhost/day14/demo1
- URL:統一資源定位符 : http://localhost/day14/demo1
- URI:統一資源辨別符 : /day14/demo1
- 擷取協定及版本:HTTP/1.1
- String getProtocol()
- 擷取客戶機的IP位址:
- String getRemoteAddr()
- 擷取請求方式 :GET
- 擷取請求頭資料
-
- String getHeader(String name):通過請求頭的名稱擷取請求頭的值
- Enumeration尖括号String> getHeaderNames():擷取所有的請求頭名稱
-
- 擷取請求體資料:
- 請求體:隻有POST請求方式,才有請求體,在請求體中封裝了POST請求的請求參數
- 步驟:
- 擷取流對象
- BufferedReader getReader():擷取字元輸入流,隻能操作字元資料
- ServletInputStream getInputStream():擷取位元組輸入流,可以操作所有類型資料
- 再從流對象中拿資料
- 擷取流對象
- 代碼示例
package cn.servletDemo.web.request; 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.BufferedReader; import java.io.IOException; import java.util.Enumeration; @WebServlet("/RequestDemo02") public class ServletRequest extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String methopd = req.getMethod(); String contextPath = req.getContextPath(); String servletPath = req.getServletPath(); String requestURI = req.getRequestURI(); StringBuffer RequsetURL = req.getRequestURL(); String requestProtocol = req.getProtocol(); String IP = req.getRemoteAddr(); Enumeration<String> headerNames = req.getHeaderNames(); System.out.printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n", methopd,contextPath,servletPath,requestURI, RequsetURL,requestProtocol,IP); while(headerNames.hasMoreElements()){ String name = headerNames.nextElement(); String value = req.getHeader(name); System.out.printf("%s\t:%s\n",name,value); } } /***結果 GET /req /RequestDemo02 /req/RequestDemo02 http://localhost:8080/req/RequestDemo02 HTTP/1.1 0:0:0:0:0:0:0:1 host :localhost:8080 connection :keep-alive upgrade-insecure-requests :1 user-agent :Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36 sec-fetch-user :?1 accept :text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,; q=0.8,application/signed-exchange;v=b3;q=0.9 sec-fetch-site :none sec-fetch-mode :navigate accept-encoding :gzip, deflate, br accept-language :zh-CN,zh;q=0.9 cookie :JSESSIONID=4973752F177A01DFD0BC110AB93AEA40; Idea-fe3516c6=e1f7407c-f751-4f0d-99cf-6bbfd9ff1826; goSessionid=wqXEMF4WFNSPwE3L9lcUSMXcLjCnLUgizfec2DipoDI%3D; SL_G_WPT_TO=zh-CN; SL_GWPT_Show_Hide_tmp=undefined; SL_wptGlobTipTmp=undefined; JSESSIONID=7DB8D0F83015408AC113950CB3E0A18B ***/ @Override protected void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException { //擷取請求消息體 //擷取字元流 BufferedReader br = req.getReader(); //讀資料 String line = null; while((line = br.readLine()) != null){ System.out.println(line); } //結果username=315019748%40qq.com&password=%E9%98%BF%E6%96%AF%E8%BE%BE } }
- html代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注冊頁面</title> </head> <body> <form action="/req/RequestDemo02" method="post"> <input type="text" placeholder="請輸入使用者名" name="username"><br> <input type="text" placeholder="請輸入密碼" name="password"><br> <input type="submit" value="注冊"> </form> </body> </html>
- 結果
- 擷取請求行資料
- 其他功能:
- 擷取請求參數通用方式:不論get還是post請求方式都可以使用下列方法來擷取請求參數
- String get(String name):根據參數名稱擷取參數值 username=zs&password=123
- String[] getParameterValues(String name):根據參數名稱擷取參數值的數組 hobby=xx&hobby=game
- Enumeration String> getParameterNames():擷取所有請求的參數名稱
- Map String,String[]> getParameterMap():擷取所有參數的map集合
- 中文亂碼問題:
- get方式:tomcat 8 已經将get方式亂碼問題解決了
- post方式:會亂碼
- 解決:在擷取參數前,設定request的編碼request.setCharacterEncoding("utf-8");
@WebServlet("/RequestDemo03") public class ServletRequest01 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //get擷取請求參數 //根據請求參數名稱擷取請求參數值 String username = req.getParameter("username"); System.out.println("get:"+username); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //post請求參數 req.setCharacterEncoding("utf-8"); //根據請求參數名稱擷取請求參數值 String username = req.getParameter("username"); System.out.println("post:"+username); } }
- 請求轉發:一種在伺服器内部的資源跳轉方式
-
- 通過request對象擷取請求轉發器對象:RequestDispatcher getRequestDispatcher(String path)
- 使用RequestDispatcher對象來進行轉發:forward(ServletRequest request, ServletResponse response)
-
- 浏覽器位址欄路徑不發生變化
- 隻能轉發到目前伺服器内部資源中,不能通路外部資源。
- 轉發實質是同一次請求
-
- 共享資料:
- 域對象:一個有作用範圍的對象,可以在範圍内共享資料
- request域:代表一次請求的範圍,一般用于請求轉發的多個資源中共享資料
-
- void setAttribute(String name,Object obj):存儲資料
- Object getAttitude(String name):通過鍵擷取值
- void removeAttribute(String name):通過鍵移除鍵值對
- 擷取ServletContext:
- ServletContext getServletContext()
- 擷取請求參數通用方式:不論get還是post請求方式都可以使用下列方法來擷取請求參數
- 擷取請求消息資料
案例:使用者登入
-
使用者登入案例需求:
1.編寫login.html登入頁面
username & password 兩個輸入框
2.使用Druid資料庫連接配接池技術,操作mysql,day14資料庫中user表
3.使用JdbcTemplate技術封裝JDBC
4.登入成功跳轉到SuccessServlet展示:登入成功!使用者名,歡迎您
- 開發步驟
- 建立項目,導入html頁面,配置檔案,jar包
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登入</title> </head> <body> <form action="/test/LoginServlet" method="post"> 使用者名:<input type="text" name="username"><br> 密碼:<input type="text" name="password"><br> <input type="submit" value="登入"> </form> </body> </html>
- 建立資料庫環境
CREATE DATABASE day14; USE day14; CREATE TABLE USER( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) UNIQUE NOT NULL, PASSWORD VARCHAR(32) NOT NULL );
- 建立包package cn.test.domain;,建立類User
package cn.test.domain; /* 使用者的實體類 */ public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
- 建立包cn.test.util,編寫工具類JDBCUtils,加載配置檔案
package cn.test.util; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; /* JDBC工具類,使用的是Druid連接配接池 */ public class JDBCUtils { private static DataSource dataSource; /* 靜态代碼塊加載配置檔案,初始化連接配接池 */ static { try { //1.加載配置檔案 Properties pro = new Properties(); //使用ClassLoader加載配置檔案,擷取位元組輸入流 InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(inputStream); //2.初始化連接配接池對象 dataSource = DruidDataSourceFactory.createDataSource(pro); } catch (Exception e) { e.printStackTrace(); } } /* 擷取連接配接池對象 */ public static DataSource getDataSource(){ return dataSource; } /* 擷取Connection對象 */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }
- 建立包cn.test.dao,建立類UserDao,提供login方法
package cn.test.dao; import cn.testT.domain.User; import cn.testT.util.JDBCUtils; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; /* 操作資料庫User表 */ public class UserDao { //聲明JDBCTemplate對象,實作共用 private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource()); //登入邏輯的完成 public User login(User loginUser){ try { //1.編寫sql String sql = "select * from user where username = ? and password = ?"; //2.調用querry方法 User user = template.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class), loginUser.getUsername(),loginUser.getPassword()); return user; } catch (DataAccessException e) { e.printStackTrace(); //一般在此處處理日志 return null; } } }
- 編寫cn.test.web.servlet.LoginServlet類
package cn.testT.web.servlet; import cn.testT.dao.UserDao; import cn.testT.domain.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; @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //設定編碼 req.setCharacterEncoding("utf-8"); //擷取請求參數 String username = req.getParameter("username"); String password = req.getParameter("password"); //封裝user對象 User loginUser = new User(); loginUser.setUsername(username); loginUser.setPassword(password); //調用UserDao的login方法 UserDao dao = new UserDao(); User user = dao.login(loginUser); //判斷user if (user == null) { //登入失敗,内部轉發 req.getRequestDispatcher("/FailServlet").forward(req, resp); } else { //登入成功 //存儲資料 req.setAttribute("user",user); //轉發 req.getRequestDispatcher("/SuccessServlet").forward(req,resp); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
- 編寫FailServlet和SuccessServlet類
package cn.testT.web.servlet; 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("/FailServlet") public class FailServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //給頁面寫一句話 //設定頁面的編碼 response.setContentType("text/html;charset=utf-8"); //輸出 response.getWriter().write("輸入錯誤,登入失敗"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } } ------------------------------------------------------------------------------------------------------------------ package cn.testT.web.servlet; import cn.testT.domain.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; @WebServlet("/SuccessServlet") public class SuccessServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //擷取request域中共享的user對象 User user = (User) request.getAttribute("user"); //給頁面寫一句話 //設定頁面的編碼 response.setContentType("text/html;charset=utf-8"); //輸出 response.getWriter().write("登入成功"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
- login.html中form表單的action路徑的寫法
- 虛拟目錄/Servlet的資源路徑
- BeanUtils工具類,簡化資料封裝
- 用于封裝JavaBean的
package cn.testT.web.servlet; import cn.testT.dao.UserDao; import cn.testT.domain.User; import org.apache.commons.beanutils.BeanUtils; 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.lang.reflect.InvocationTargetException; import java.util.Map; @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //設定編碼 req.setCharacterEncoding("utf-8"); // //擷取請求參數 // String username = req.getParameter("username"); // String password = req.getParameter("password"); // //封裝user對象 // User loginUser = new User(); // loginUser.setUsername(username); // loginUser.setPassword(password); //擷取所有請求參數 Map<String, String[]> parameterMap = req.getParameterMap(); //建立user對象 User loginUser = new User; //使用BeanUtils封裝 try { BeanUtils.populate(loginUser,parameterMap); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } //調用UserDao的login方法 UserDao dao = new UserDao(); User user = dao.login(loginUser); //判斷user if (user == null) { //登入失敗,内部轉發 req.getRequestDispatcher("/FailServlet").forward(req, resp); } else { //登入成功 //存儲資料 req.setAttribute("user",user); //轉發 req.getRequestDispatcher("/SuccessServlet").forward(req,resp); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } }
- JavaBean:标準的Java類(上述User類,一般再domain目錄下)
- 要求:
- 類必須被public修飾
- 必須提供空參的構造器
- 成員變量必須使用private修飾
- 提供公共setter和getter方法
- 功能:封裝資料
- 要求:
-
- setProperty()與getProperty()
- populate(Object obj , Map map):将map集合的鍵值對資訊,封裝到對應的JavaBean對象中
- 注意:以上操作的是屬性:setter和getter方法截取後的産物,例如:getUsername() --> Username--> username,不是JavaBean的成員變量