在上一節(jié)中,我們系統(tǒng)的學習了請求響應在Servlet中
service()
方法的第一個形參HttpServletRequest(請求)對象,這一節(jié)中我們將學習它的兄弟,service()
方法的第二個形參HttpServletResponse(響應)對象
一、什么是HttpServletResponse
在我們已然熟悉的瀏覽器訪問Servlet的過程中。Request和Response 對象分別代表請求和響應:通過Request對象獲取客戶端數(shù)據(jù);通過 Response 對象向客戶端輸出數(shù)據(jù):service()
方法中形參接收的是HttpServletResponse接口的實例化對象,它繼承自ServletResponse接口,專門用來封裝HTTP響應消息,由于HTTP響應消息分為狀態(tài)行、響應消息頭、消息體三部分(詳見HTTP協(xié)議理論與服務器請求響應原理小節(jié)),因此在HttpServletResponse中定義了狀態(tài)行、響應消息頭、消息體三部分。
- 狀態(tài)行部分
響應消息頭包含了關于響應的附加信息,例如內(nèi)容類型、內(nèi)容長度、緩存控制等。由setStatus(int status)
方法實現(xiàn),該方法用于設置HTTP響應消息的狀態(tài)碼,并生成相應代碼;默認會生成一個狀態(tài)碼為200的狀態(tài)行; - 響應消息頭部分
響應消息頭包含了關于響應的附加信息,例如內(nèi)容類型、內(nèi)容長度、緩存控制等??梢允褂?code>setHeader(String name, String value)方法設置響應消息頭的字段和值,例如setHeader("Content-Type", "text/html")
設置內(nèi)容類型為HTML。如果要設置相同字段的多個值,可以使用addHeader(String name, String value)
方法,例如addHeader("Set-Cookie", "cookie1=value1")
。此外還可以使用一些特定的方法來設置常見的響應消息頭,例如setContentType(String type)
、setContentLength(int len)
等 - 消息體部分
消息體包含了實際的響應數(shù)據(jù)??梢酝ㄟ^獲取ServletOutputStream或PrintWriter對象來寫入響應消息體。getOutputStream()
方法返回一個可以寫入二進制數(shù)據(jù)的ServletOutputStream對象。getWriter()
方法返回一個可以寫入字符數(shù)據(jù)的PrintWriter對象。
可以使用這些對象的方法將數(shù)據(jù)寫入響應消息體,例如print(String s)、write(byte[] b)
等。
二、響應數(shù)據(jù)的常用方法
接收到客戶端請求后,可以通過HttpServletResponse對象直接進行響應,響應時需要獲取輸出流。
有兩種形式:
-
getWriter()
獲取字符流(只能響應字符串) -
getOutputStream()
獲取字節(jié)流(能響應一切數(shù)據(jù))
響應回的數(shù)據(jù)到客戶端被瀏覽器解析
注意:兩者不能同時使用
實例
在start.java導入PrintWriter類,并在service()中寫入測試代碼
// 獲取字符輸出流
PrintWriter writer = resp.getWriter();
//輸出數(shù)據(jù)
writer.write("Hello");
啟動服務器,在瀏覽器中訪問得
在start.java中導入ServletOutputStream類,并在service()中寫入測試代碼
//得到字節(jié)輸出流
ServletOutputStream out = resp.getOutputStream();
// 輸出數(shù)據(jù)
out.write("Hi".getBytes());
啟動服務器,在瀏覽器中訪問得
但當兩者同時使用時
start.java
package www.caijiyuan;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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("/start")
public class start extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 獲取字符輸出流
PrintWriter writer = resp.getWriter();
//輸出數(shù)據(jù)
writer.write("Hello");
//得到字節(jié)輸出流
ServletOutputStream out = resp.getOutputStream();
// 輸出數(shù)據(jù)
out.write("Hi".getBytes());
}
}
啟動服務器,在瀏覽器中訪問,只得到了第一個的打印內(nèi)容
這是為什么呢?查看報錯信息原來是
getWriter()
已經(jīng)調(diào)用過response對象了,如果再響應一次response對象就已經(jīng)不存在了
三、響應亂碼問題
在上一節(jié)中我們使用request.setCharacterEncoding("UTF-8");
解決了請求時中文亂碼的問題,同樣,在響應時也存在中文亂碼問題。這是因為服務器響應的數(shù)據(jù)也會經(jīng)過網(wǎng)絡傳輸,服務器端有一種編碼方式,在客戶端也存在一種編碼方式,當兩端使用的編碼方式不同時則出現(xiàn)亂碼。
字符流亂碼
對于getWriter()
獲取到的字符流,響應中文必定出亂碼,由于服務器端在進行編碼時默認會使用ISO-8859-1格式的編碼,該編碼方式并不支持中文。要解決該種亂碼只能在服務器端告知服務器使用一種能夠支持中文的編碼格式,這也是我們在解決請求時中文亂碼的方法
response.setCharacterEncoding("UTF-8");
此時還只完成了一半的工作
要保證數(shù)據(jù)正確顯示,還需要指定客戶端的解碼方式
response.setHeader("content-type", "text/html; charset=UTF-8");
兩端指定編碼后,亂碼就解決了。一句話:保證發(fā)送端和接收端的編碼一致
實例
我們在start.java的service()中寫入測試測試代碼,試圖打印中文
// 獲取字符輸出流
PrintWriter writer = resp.getWriter();
//輸出數(shù)據(jù)
writer.write("湯米尼克");
啟動服務器,在瀏覽器中訪問,發(fā)現(xiàn)輸出中文亂碼
設置服務器和客戶端的編碼格式統(tǒng)一
// 設置服務端的編碼
resp.setCharacterEncoding("UTF-8");
// 設置客戶端的響應類型及編碼
resp. setHeader("content-type", "text/html; charset=UTF-8");
// 獲取字符輸出流
PrintWriter writer = resp.getWriter();
// 輸出數(shù)據(jù)
writer.write("湯米尼克");
重啟瀏覽器,再在瀏覽器中訪問就解決問題了
理解了原理,其實我們還可以同時設置客戶端和服務端的編碼方式
response.setContentType( "text/html; charset=UTF-8");
這一句就可以替換上面的兩句
字節(jié)流亂碼
對于getOutputStream()
方式獲取到的字節(jié)流,響應中文時,由于本身就是傳輸?shù)淖止?jié),所以此時可能出現(xiàn)亂碼,也可能正確顯示。當服務器端給的字節(jié)恰好和客戶端使用的編碼方式一致時則文本正確顯示,否則出現(xiàn)亂碼。無論如何我們都應該準確掌握服務器和客戶端使用的是那種編碼格式,以確保數(shù)據(jù)正確顯示。
因此,字節(jié)流亂碼的解決方式與上面字符流亂碼的解決方式一樣,在響應發(fā)出之前同時設置服務器和客戶端的編碼格式統(tǒng)一即可
response.setContentType( "text/html; charset=UTF-8");
四、重定向:sendRedirect
重定向是一種服務器為指導的客戶端行為。
怎么理解這句話呢?客戶端發(fā)出一個請求,被服務器接收處理后進行響應,在響應的同時,服務器會給客戶端一個新的地址(下次請求的地址),當客戶端接收到響應后,會立刻、馬上自動根據(jù)服務器給的新地址發(fā)起第二個請求,服務器接收請求并作出響應,重定向完成。可以看出這個過程中有兩個請求存在,其中兩個Servlet的Request對象并不共享、不能傳值,屬于客戶端行為。
在Servlet中重定向的語句為
response.sendRedirect("url");
實例:從start.java重定向到after.java的過程
在start.java的service()
中寫入重定向前的測試代碼
System.out.println("這里是start");
resp.sendRedirect("after");
在after.java的service()
中寫入重定向到底測試代碼
System.out.println("這里是after");
啟動服務器,在瀏覽器中輸入start的地址
回車訪問后地址立即跳轉到after,說明重定向的地址欄會發(fā)生改變
同時控制臺輸出了
那么重定向在服務器中的響應頭是如何實現(xiàn)的?
如下圖,在開發(fā)者工具中打開響應頭的內(nèi)容
會發(fā)現(xiàn)start文件響應行的狀態(tài)碼是302,這就是重定向的狀態(tài)碼
并且響應頭鍵值對中Location鍵的值就是要重定向到的地址:after文件
這與我們在第一節(jié) HTTP協(xié)議理論與服務器請求響應原理中學習的響應頭的知識首尾呼應起來了
請求轉發(fā)和重定向的區(qū)別
上一節(jié)中我們學習了Request對象的請求轉發(fā),這一節(jié)又學習了Response對象的重定向,兩兄弟讓人傻傻分不清,必須好好區(qū)分區(qū)分文章來源:http://www.zghlxwxcb.cn/news/detail-833526.html
請求轉發(fā) | 重定向 |
---|---|
request.getRequestDispatcher("url").forward(request, response); |
response.sendRedirect("url"); |
服務器端行為 | 客戶端行為 |
一次請求,Request域中數(shù)據(jù)共享 | 兩次請求,Request域中數(shù)據(jù)不共享 |
地址欄不發(fā)生變化 | 地址欄發(fā)生變化 |
跳轉只能在當前站點內(nèi) | 跳轉任意地址 |
在這一節(jié)中我們學習了HttpServletResponse對象,學習了字符流字節(jié)流響應方法、重定向方法。不禁思考,Servlet作為“后端”,在Web交互中最重要的作用就是傳遞各種數(shù)據(jù),但目前我們學到的傳值的方法還知之甚少,在下一節(jié)中我們將學習Cookie對象、HttpSession對象、ServletContext對象,它們作為不同特點的容器在Servlet上可以實現(xiàn)不同范圍的傳值文章來源地址http://www.zghlxwxcb.cn/news/detail-833526.html
到了這里,關于板塊一 Servlet編程:第四節(jié) HttpServletResponse對象全解與重定向 來自【湯米尼克的JAVAEE全套教程專欄】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!