Request & Response
- request: 由Http請求封裝而成的對象,用于接收瀏覽器提交的數(shù)據(jù)。從這個(gè)對象可以取出(get)瀏覽器發(fā)送的數(shù)據(jù)。
- response: 用于生成Http響應(yīng)的對象,將服務(wù)器的數(shù)據(jù)發(fā)送給瀏覽器。這個(gè)對象可以設(shè)置(set)發(fā)送給瀏覽器的數(shù)據(jù).
Response對象
用于生成http響應(yīng)信息,對于開發(fā)人員來講,就是 向response 對象中添加信息即可。
響應(yīng)首行
HTTP/1.1 200 OK
void setStatus(int sc)
void sendError(int sc)
void sendError(int sc, String msg)
響應(yīng)頭
void setHeader(String name, String value) 設(shè)置鍵值對.
void setDateHeader(String name, long date) 設(shè)置鍵值對.
void setIntHeader(String name, int value) 設(shè)置鍵值對.
void addHeader(String name, String value) 添加鍵值對.
void addDateHeader(String name, long date)添加鍵值對.
void addIntHeader(String name, int value) 添加鍵值對.
setHeader(name, value):如果Header中沒有定義則添加,如果已定義則用新的value覆蓋原用value值。
addHeader(name, value):如果Header中沒有定義則添加,如果已定義則保持原有value不改變。
響應(yīng)空行
響應(yīng)正文
// 需要給瀏覽器的資源
getWriter(); 字符流
getOutputStream(); 字節(jié)流
一些例子
手動(dòng)向?yàn)g覽器 發(fā)送404錯(cuò)誤狀態(tài)碼。
package response;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Aservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendError(404, "哈哈");
}
}
訪問BServlet,3秒后瀏覽器自動(dòng)跳轉(zhuǎn)到百度。
package response;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Bservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// <meta http-equiv="Refresh" content="3;url=地址" >
// 設(shè)置編碼防止亂碼
response.setContentType("text/html;charset=utf-8");
// response.addHeader("Refresh", "3;url=https://www.baidu.com");
PrintWriter out = response.getWriter();
// 讓頁面有倒計(jì)時(shí)的效果
response.getWriter().write("您將在<span id='one'>3</span>秒后跳轉(zhuǎn)!" +
"<script type='text/javaScript' >" +
"var span = document.getElementById('one');" +
"var i =3;" +
"function fun(){" +
"i--;" +
"if(i>=0){" +
"span.innerHTML = i;" +
"}" +
"}" +
"window.setInterval(fun,1000);" +
"</script>");
}
}
中文亂碼
字節(jié)流
保證編碼碼表和解碼碼表一致,一般utf-8
package response;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Cservlet extends HttpServlet {
// 編碼碼表和解碼碼表一致就行
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 設(shè)置解碼碼表
response.setContentType("text/html;charset=utf-8");
response.getOutputStream().write("哈哈".getBytes("utf-8")); // 設(shè)置編碼碼表,不一致會出現(xiàn)亂碼
}
}
字符流
setContentType方法如果發(fā)現(xiàn)你填寫碼表,那么會同時(shí)自動(dòng)設(shè)置編碼碼表。意思就是填寫一此碼表即可。
package response;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Dservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("哈哈");
}
}
結(jié)論
- 輸出中文建議使用字符流
- 解決字符流亂碼 使用setContentType放可以同時(shí)設(shè)置編碼解碼兩端的碼表.
- 注意: 碼表的設(shè)置一定放到輸出之前
- 注意: 字符流與字節(jié)流不能同時(shí)使用
向servlet發(fā)送圖片
package response;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Eservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
InputStream is = getServletContext().getResourceAsStream("/wallpaper.png");
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
os.flush();
// 調(diào)用別人方法開的流,一般無需關(guān)閉(他肯定會關(guān))
// 自己new出來的流需要關(guān)閉
}
}
}
從Servlet下載文件
package response;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Fservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
InputStream is = getServletContext().getResourceAsStream("/kxml2-src-2.3.0.zip");
// 原則: 凡是響應(yīng)正文中需要輸出內(nèi)容, 一定要設(shè)置content-type頭
ServletContext sc = getServletContext();
// 只會截取后綴名zip
String type = sc.getMimeType("abc.zip");
response.setContentType(type);
// 設(shè)置這里讓瀏覽器知道我們下載的文件名,要不默認(rèn)使用Fservlet這個(gè)名稱,且沒有后綴名
response.setHeader("Content-Disposition", "attachment;filename=kxml2-src-2.3.0.zip");
OutputStream os = response.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
os.flush();
}
}
}
Request對象
請求首行
請求方式 請求路徑 協(xié)議/版本號
String getMethod() // 獲得請求方式
request.getContextPath() // /req_res 獲得項(xiàng)目路徑
request.getQueryString(): name=tom?age=19 // 獲得請求路徑中的參數(shù)
request.getRequestURI(): // /req_res/AServlet 獲得當(dāng)前訪問的相對路徑,相對主機(jī)路徑
request.getRequestURL(): // http://localhost:8080/req_res/AServlet 獲得當(dāng)前訪問的絕對路徑
request.getServletPath(): // /AServlet 獲得servlet路徑
String getScheme() // 獲得協(xié)議協(xié)議(如http)
請求頭
鍵 : 值
request.getContentLength() // 返回正文內(nèi)容長度,-1表示沒有
request.getContentType() // null 返回正文內(nèi)容類型
request.getLocale() // zh_HANS_CN // 獲得accept-language:zh_CN
request.getServerName() // localhost 獲得主機(jī)名稱
request.getServerPort() // 8080 獲得訪問端口號
String getHeader(String name) // 根據(jù)鍵獲得值(值只有一個(gè))
long getDateHeader(String name)
int getIntHeader(String name)
Enumeration getHeaderNames() // 獲得所有請求頭的名字
Enumeration getHeaders(String name) // 根據(jù)鍵獲得值(值有多個(gè))
請求空行
請求正文
post請求才有=> 請求參數(shù) => name=tom&age=18
String getParameter(String name) // 根據(jù)參數(shù)鍵獲得參數(shù)值
Map<String,String[]> getParameterMap() // 返回封裝參數(shù)的Map
Enumeration getParameterNames() // 獲得所有參數(shù)的鍵
String[] getParameterValues(String name) // 根據(jù)參數(shù)鍵獲得參數(shù)值(值有多個(gè))
一圖勝千言。

獲得表單數(shù)據(jù)
使用了GET和POST兩種請求方法。
下面是兩個(gè)表單,提交方式分別是GET和.
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
...
<body>
<form action="/req_res/Gservlet" method="get">
用戶名:<input type="text" name="name" /> <br />
密碼:<input type="password" name="password" /> <br />
<input type="submit" />
</form>
<hr>
<form action="/req_res/Gservlet" method="post">
用戶名:<input type="text" name="name" /> <br />
密碼:<input type="password" name="password" /> <br />
<input type="submit" />
</form>
</body>
</html>
package request;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Gservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Enumeration<String> en = request.getParameterNames();
while (en.hasMoreElements()) {
String key = en.nextElement();
String value = request.getParameter(key);
System.out.println(key + " : " + value);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Enumeration<String> en = request.getParameterNames();
while (en.hasMoreElements()) {
String key = en.nextElement();
String value = request.getParameter(key);
System.out.println(key + " : " + value);
}
}
}
上面的表單中輸入中文,輸出會亂碼。
解決亂碼--GET
可以在/comf/server.xml里面,配置服務(wù)器的解碼碼表。這針對范圍很廣。
<Connector port="8080" protocol="HTTP/1.1"
URIEncoding="UTF-8"
connectionTimeout="20000"
redirectPort="8443" />
解決亂碼--POST
POST提交和GET提交區(qū)別只是服務(wù)器解碼時(shí)間點(diǎn)不一樣,其他沒區(qū)別。
GET: 請求一旦到達(dá)服務(wù)器會立即解碼參數(shù)
POST: 調(diào)用獲得參數(shù)時(shí)候才會解碼
所以解決POST提交亂碼,只需要調(diào)用參數(shù)方法前,設(shè)置一下解碼碼表就。
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
Enumeration<String> en = request.getParameterNames();
while (en.hasMoreElements()) {
String key = en.nextElement();
String value = request.getParameter(key);
System.out.println(key + " : " + value);
}
}
請求轉(zhuǎn)發(fā)
意義在于使得Servlet和JSP分工明確。
- Servlet處理業(yè)務(wù)邏輯--本質(zhì)上是Java代碼,主要是在service(req, res);中操作
- JSP負(fù)責(zé)顯示結(jié)果

這里還沒學(xué)JSP技術(shù),暫時(shí)用Eservlet代替JSP使用。
下面是Dservlet
package response;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Dservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("我負(fù)責(zé)處理業(yè)務(wù)邏輯");
// 裝發(fā)給Eservlet
request.getRequestDispatcher("/Eservlet").forward(request, response);
}
}
下面是Eservlet
package response;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 訪問Dservlet轉(zhuǎn)發(fā)過來
public class Eservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我負(fù)責(zé)顯示結(jié)果");
}
}
Dservlet和Eservlet怎么共享數(shù)據(jù)
和SevletContext類似,Request域,在request對象中喲一個(gè)map,把處理結(jié)果放在Dervlet中,再從Eservlet中取出來。
Dservlet
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("我負(fù)責(zé)處理業(yè)務(wù)邏輯");
String name = "value"; // 假設(shè)這個(gè)值是從數(shù)據(jù)庫中取出來的
// 將name放入Request域中
request.setAttribute("key", name);
request.getRequestDispatcher("/Eservlet").forward(request, response);
}
Eservlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("我負(fù)責(zé)顯示結(jié)果");
String value = (String) request.getAttribute("key");
System.out.println("Eservlet: " + value);
}
轉(zhuǎn)發(fā)時(shí)候要注意
- 不能在正轉(zhuǎn)發(fā)的Servlet中(比如這里的Dervlet),向?yàn)g覽器輸入任何正文響應(yīng)。因?yàn)榧磳⑥D(zhuǎn)發(fā)了,也不會顯示出來。但是接收 轉(zhuǎn)發(fā)的Eservlet中可以向?yàn)g覽器輸入響應(yīng)。但是添加頭是允許的
- 在轉(zhuǎn)發(fā)Servlet后,不允許再操作request和response對象。直白點(diǎn)說就是
request.getRequestDispatcher("/Eservlet").forward(request, response);這句之后,一般不在其后寫代碼了,通常這句是最后一行。
重定向和轉(zhuǎn)發(fā)的區(qū)別
-
分別是發(fā)送了幾次請求
- 重定向:兩次
- 轉(zhuǎn)發(fā):一次
能不能訪問項(xiàng)目之外的地址
- 重定向:可以
- 轉(zhuǎn)發(fā):不可以(轉(zhuǎn)發(fā)是內(nèi)部的事)
- 能不能使用request域共享數(shù)據(jù)
- 重定向:不可以
- 轉(zhuǎn)發(fā):可以
- 地址欄會不會發(fā)生變化
- 重定向: 一般會
- 轉(zhuǎn)發(fā):不會
-
請求方式是否會發(fā)生改變
- 重定向: 有可能,重定向的第二個(gè)請求一定是GET
- 轉(zhuǎn)發(fā):不會
請求包含
往往是在多個(gè)jsp中使用,其中一個(gè)jsp封裝相同部分,其他的jsp凡是要是顯示相同的部分時(shí),就可以把裝著這相同部分的jsp包含進(jìn)來。
包含與轉(zhuǎn)發(fā)的區(qū)別
- 轉(zhuǎn)發(fā)中只能設(shè)置頭,而不能向響應(yīng)正文輸出 < -- > 包含是兩者都可發(fā)送
- 轉(zhuǎn)發(fā)后不能在對req和res再進(jìn)行操作 < -- > 包含中沒有這個(gè)限制
一個(gè)包含的小例子
其中Jservlet作為封裝相同內(nèi)容的那個(gè)。
package request;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Jservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("這是相同部分");
}
}
Iservlet
package request;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Iservlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("這是第一部分");
// 包含
request.getRequestDispatcher("/Jservlet").include(request, response);
response.getWriter().println("這是第二部分");
}
}
這里只在Iservlet中指定碼表即可,因?yàn)槭峭粋€(gè)響應(yīng),所以不必用Jservlet指定,也會正常顯示不會出現(xiàn)亂碼。
by @sunhaiyu
2017.3.27