JavaWeb學習四(HttpServletResponse和HttpServletRequest)
一.伺服器處理請求流程
1.請求響應流程圖
- 伺服器每次收到請求時,都會為這個請求開闢一個新的執行緒
- 伺服器會把客戶端的請求資料封裝到request物件中
- request就是請求資料的載體!(筷子)
- 伺服器還會建立response物件,這個物件與客戶端連線在一起
- 它可以用來向客戶端傳送響應(手機)
二.HttpServletResponse
- ServletResponse–> 與協議無關的型別
- HttpServletResponse –>與Http協議相關的型別
1.狀態碼
- sendError(int sc) –>傳送錯誤狀態碼,例如404 500
- sendError(int sc,String msg) –>傳送錯誤狀態碼,還可以帶一個錯誤資訊
- setStatus(int sc)–> 傳送成功的狀態碼 可以用來發送302
public class CServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(404,"成都東軟校園網無法訪問" );
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
訪問此Servlet效果如下圖:
2.響應頭
Content-Type Refresh Location等等
頭就是一個鍵值對,可能會存在一個頭(一個名稱 一個值),也可能會存在一個頭(一個名稱 多個值)
setHeader(String name,String value):適用於單值的響應頭
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setHeader("aaa","AA");
response.setStatus(200);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
- addHeader(String name,String value):使用於多值的響應頭
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.addHeader("aaa","AAA");
response.addHeader("aaa", "AA");
response.addHeader("aaa", "A");
response.setStatus(200);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
- setIntHeader(String name,int value):適用於單值的int型別的響應頭
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setIntHeader("aaa",1);
response.setStatus(200);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
- addIntHeader(String name,int value):適用於多值的int型別的響應頭
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.addIntHeader("aaa",1);
response.addIntHeader("aaa",22);
response.addIntHeader("aaa",333);
response.setStatus(200);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
- setDateHeader(String name,long value):適用於單值的毫秒型別的響應頭
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setDateHeader("expires",60*60*24*1000);//快取24小時
response.setStatus(200);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
不過注意一般在開發的時候會這麼設定,快取大多自然不好
response.setDateHeader("expires",-1);//設定過期時間為-1
- addDateHeader(String name,long value):適用於多值的毫秒型別的響應頭
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.addDateHeader("expires",60*60*24*1000);//快取24小時
response.addDateHeader("expires",60*60*24*10000);//快取240小時
response.setStatus(200);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
3.案例
(1).傳送302,設定Location頭,完成重定向
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("DServlet...");
response.setHeader("Location","/javaweb2/EServlet");
response.setStatus(302);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
public class EServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("EServlet...");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
訪問DServlet,控制檯打印出
DServlet...
EServlet...
大致圖解
(2).定時重新整理,設定Refresh頭,你可以把它理解成,定時的重定向
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter printWriter=response.getWriter();
printWriter.println("您好,5秒鐘將進入重定向");
response.setHeader("Refresh","5;URL=/javaweb2/EServlet");
}
}
public class EServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("你看到不是亂碼!");
}
}
(3).禁止瀏覽器快取
public class FServlet 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);
response.getWriter().print("hello world");
}
}
注意:<meta>標籤可以代替響應頭
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8">
<meta http-equiv="Content-Type" content="Cache-Control"; charset="no-cache">
...
4.響應體
響應體通常是html,也可以是圖片
response的兩個流
- ServletOutputStream 用來向客戶端傳送位元組資料
ServletOutputStream out=response.getOutputStream();
- PrintWriter: 用來向客戶端傳送字元資料 需要設定編碼
PrintWriter writer=response.getWriter();
public class GServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String ss="hello world";
byte[] bys=ss.getBytes();
response.getOutputStream().write(bys);
String path="E:/F/黑黑.jpg";
FileInputStream fis=new FileInputStream(path);
byte[] byss=IOUtils.toByteArray(fis);//將圖片轉換成位元組陣列
response.getOutputStream().write(byss);
}
}
注意兩個流不能同時使用
5.直接進行重定向
public class DServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("DServlet...");
response.sendRedirect("/javaweb2/EServlet");//直接進行重定向的方法
}
}
public class EServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("EServlet...");
}
}
控制檯列印
DServlet...
EServlet...
三.HttpServletRequest(封裝了客戶端所有的請求資料)
1.請求協議
- 請求行
- 請求頭
- 空行
- 請求體(GET提交方式是沒有請求體的)
2.常用方法
(1).獲取常用資訊
A.獲取客戶端ip
request.getRemoteAddr();
B.獲取請求方式
request.getMethod();//可能是POST 也可能是GET
(2).獲取HTTP請求頭
String getHeader(String name);//適用於單值頭
int getIntHeader(Stirng name);//適用於單值int型別的請求頭
long getDateHeader(String name);//適用於單值毫秒型別的請求頭
Enumeration <String> getHeaders(String name);//適用於多值請求頭
舉例
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String addr=request.getRemoteAddr();
String method=request.getMethod();
String userAgent=request.getHeader("user-Agent");
System.out.println("addr:"+addr);
System.out.println("請求方式:"+method);
System.out.println("user-Agent:"+userAgent);
}
}
列印
addr:0:0:0:0:0:0:0:1
請求方式:GET
user-Agent:Mozilla/5.0 (Windows NT 6.2; Win64; x64; Trident/7.0; rv:11.0) like Gecko
user-Agent包括了很多資訊,訪問資源瀏覽器的資訊,系統資訊等
(3).獲取請求URL
- String getScheme():獲取協議 http
- String getServerName():獲取伺服器名 localhost
- String getServerPort():獲取伺服器埠 8080
- String getContextPath():獲取專案名
- String getServletPath():獲取Servlet路徑
- String getQueryString():獲取引數部分 即問號後面的部分
- String getRequestURI():獲取請求URI
- StringBuffer getRequestURL():獲取請求URL
舉例
public class BServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String http=request.getScheme();
String ServerName=request.getServerName();
int Serverport=request.getServerPort();
String ContextPath=request.getContextPath();
String ServletPath=request.getServletPath();
String QueryString=request.getQueryString();
String uri=request.getRequestURI();
StringBuffer url=request.getRequestURL();
System.out.println("協議名:"+http);
System.out.println("伺服器名:"+ServerName);
System.out.println("伺服器埠:"+Serverport);
System.out.println("專案名:"+ContextPath);
System.out.println("servlet的路徑:"+ServletPath);
System.out.println("引數:"+QueryString);
System.out.println("uri:"+uri);
System.out.println("url:"+url.toString());
}
}
列印
協議名:http
伺服器名:localhost
伺服器埠:8080
專案名:/javaweb3
servlet的路徑:/BServlet
引數:null //因為你是get請求所以沒有引數
uri:/javaweb3/BServlet
url:http://localhost:8080/javaweb3/BServlet
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/javaweb3/BServlet" method="get">
<input type="text" name="text"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
列印
協議名:http
伺服器名:localhost
伺服器埠:8080
專案名:/javaweb3
servlet的路徑:/BServlet
引數:text=1444
uri:/javaweb3/BServlet
url:http://localhost:8080/javaweb3/BServlet
(4).防盜鏈
如果請求不是通過本站的超連結發出的,傳送錯誤狀態碼404,Referer,這個請求頭表示請求的來源!
public class CServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String Referer=request.getHeader("Referer");
System.out.println(Referer);
if(Referer==null||Referer.contains("localhost")) {//直接訪問Referer值是null
response.sendRedirect(request.getContextPath()+"/DServlet");
}else {
response.sendError(404, "滾開");
}
}
}
(5).獲取請求引數
請求引數是由客戶端傳送給伺服器的 有可能是在請求體中(POST)
- String getParameter(String name):獲取指定名稱的請求引數值,適用於單值請求引數
- String [] getParameterValues(String name):獲取指定名稱的請求引數值,適用於多值請求引數
- Enumeration
<String>
getParameterNames():獲取所有請求引數名稱 - Map
<String,String[]>
getParameterMap():獲取所有請求引數,其中Key為引數名,value為引數值
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/javaweb3/EServlet">
使用者名稱:<input type="text" name="username"><br/>
密碼:<input type="password" name="password"><br/>
性別:<input type="radio" name="sex" value="nan">男
<input type="radio" name="sex" value="nv">女<br/>
愛好:<input type="checkbox" name="love" value="ppq">乒乓球
<input type="checkbox" name="love" value="lq">籃球
<input type="checkbox" name="love" value="ymq">羽毛球<br/>
<input type="submit" value="提交">
</form>
</body>
</html>
public class EServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username=request.getParameter("username");
String password=request.getParameter("password");
System.out.println("username:"+username);
System.out.println("password:"+password);
String [] loves=request.getParameterValues("love");
for(String s:loves) {
System.out.println("love:"+s);
}
Enumeration<String> enumeration=request.getParameterNames();
while(enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
Map<String,String[]> map=request.getParameterMap();
for(String name:map.keySet()) {
String [] values=map.get(name);
System.out.println(name+":"+Arrays.toString(values));
}
}
}
列印
username:123
password:123
love:ppq
love:lq
love:ymq
username
password
sex
love
username:[123]
password:[123]
sex:[nan]
love:[ppq, lq, ymq]
(6).請求轉發和請求包含
RequestDispatcher rd=request.getRequestDispatcher("/MyServlet")
使用request獲取RequestDispatcher物件,方法的引數是被轉發或包含的Servlet路徑
A.請求轉發
public class OneServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("OneServlet...");
resp.setHeader("aaa","AAA");//設定響應頭
resp.getWriter().print("aaaaaaa");//設定響應體
req.getRequestDispatcher("/TwoServlet").forward(req, resp);
}
}
public class TwoServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("TwoServlet...");
response.getWriter().print("bbbbbb");//設定響應體
}
}
總結
由下一個Servlet完成響應體,當前Servlet可以設定響應頭(留頭不留體)
如果把OneServlet改成如下
public class OneServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("OneServlet...");
resp.setHeader("aaa","AAA");
for(int i=0;i<1024*24+1;i++) {
resp.getWriter().print("a");
}
//相當於呼叫了TwoServlet的service的方法
req.getRequestDispatcher("/TwoServlet").forward(req, resp);
}
}
為什麼打印出了?不是留頭不留體嘛?
看吧!控制檯還是報錯了的!
總結
在請求轉發的時候,最好不要做過多的操作,過多的操作情況下,就好別使用轉發
B.請求轉發
public class OneServlets extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("OneServlets...");
response.setHeader("aaa","AAA");
response.getWriter().print("OneServlet one!!!");
request.getRequestDispatcher("/TwoServlets").include(request, response);
}
}
public class TwoServlets extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("TwoServlets...");
response.getWriter().print("TwoServlet two!!!");
}
}
總結
由兩個Servlet共同未完成響應體(都留)
無論是請求轉發還是請求包含,都在一個請求範圍內,使用同一個request和response!
(7).request域
Servlet中三大域物件: request session application
- void setAttribute(String name,Object value)
- object getAttribute(String name)
- void removeAttribute(String name)
同一請求範圍內使用request.setAttribute(),request.getAttribute()來傳值
(8).請求轉發和重定向的區別
- 請求轉發是一個請求一次響應,而後者是兩次請求兩次響應
- 請求轉發位址列不變化,而後者顯示後一個請求的地址
- 請求轉發只能轉發到本專案其他Servlet,而後者不只能重定向到本專案的其他Servlet,還能定向到其他專案
- 請求轉發是伺服器端行為,只需給出轉發的Servlet路徑,而後者需要給出requestURI ,即包含專案名
- 請求轉發和重定向效率,轉發高 ,因為是一個請求
- 需要位址列發生變化,那麼必須重定向
- 需要在下一個Servlet中獲取request域中的資料,必須要使用轉發
END!!!!!!!!