Java?Servlet響應(yīng)httpServletResponse過程詳解
一、核心方法
1.setStatus
設(shè)置響應(yīng)狀態(tài)碼 如果沒有調(diào)用這個方法,默認(rèn)返回200狀態(tài)碼(前提:正常執(zhí)行,沒有異常) 如果出現(xiàn)異常,返回500
前端代碼:
<body>
<h3>設(shè)置響應(yīng)頭</h3>
<input type="text" id="status">
<br>
<button onclick="setStatus()">提交</button>
</body>
<script>
function setStatus(){
//js中發(fā)送請求:(1)ajax(2)直接修改url
let status = document.querySelector("#status");
//后端會設(shè)置文本框輸入的值為響應(yīng)狀態(tài)碼:嚴(yán)格來做需要驗證(省略)
window.location.href = "response?status="+status.value;
}
</script>后端代碼:
@WebServlet("/response")
public class ResponseStudyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//獲取請求發(fā)送的queryString數(shù)據(jù):status=xxx
String status = req.getParameter("status");
resp.setStatus((Integer.parseInt(status)));
resp.getWriter().write("設(shè)置響應(yīng)狀態(tài)碼成功");
}
}前端顯示:

提交后fiddler抓包:

2.setHeader(String name,String value)
設(shè)置響應(yīng)頭
響應(yīng)頭name鍵已有,會覆蓋原有的鍵值對
前端代碼:
<h3>設(shè)置響應(yīng)頭</h3> <a href="response" rel="external nofollow" >設(shè)置</a>
后端代碼:
//設(shè)置響應(yīng)頭的鍵值對,鍵可以是標(biāo)準(zhǔn)的http響應(yīng)頭的鍵,也可以是自定義的
//響應(yīng)狀態(tài)碼是301,302,307,響應(yīng)頭有Location字段,才是重定向
resp.setHeader("Location","http://www.baidu.com");
resp.setHeader("username","張三");fiddler抓包結(jié)果:

3.addHeader(String name,String value)
設(shè)置響應(yīng)頭
響應(yīng)頭name鍵已有,不會影響,添加一個新的
這兩個了解即可
4.setContentType(String type)
設(shè)置響應(yīng)頭Content-Type的值,等同于setHeader(“Content-Type”,String type) 因為Content-Type是標(biāo)識body的數(shù)據(jù)格式,所以還需要設(shè)置body的內(nèi)容
1.響應(yīng)一個網(wǎng)頁
//響應(yīng)html:設(shè)置響應(yīng)的Content-Type
resp.setContentType("text/html; charset=utf-8");
可以返回靜態(tài)和動態(tài)網(wǎng)頁
兩種方式展示:
前端代碼:
<body>
<h3>返回響應(yīng)正文為簡單的html</h3>
<a href="html?type=1" rel="external nofollow" >查看</a>
<h3>返回響應(yīng)正文為復(fù)雜的html(動態(tài)變化的)</h3>
<input type="text" id="username" placeholder="輸入姓名">
<br>
<button onclick="toWelcome()">跳轉(zhuǎn)</button>
</body>
<script>
function toWelcome(){
let username = document.querySelector("#username");
window.location.href = "html?type=2&username="+username.value;
}
</script>后端代碼:
@WebServlet("/html")
public class HTMLTypeServlet extends HttpServlet {
//html?type=...
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//響應(yīng)html:設(shè)置響應(yīng)的Content-Type
resp.setContentType("text/html; charset=utf-8");
PrintWriter pw = resp.getWriter();
//獲取queryString中,type的值
String type = req.getParameter("type");
if("1".equals(type)){//返回簡單的html
pw.println("<h3>獲取網(wǎng)頁成功</h3>");
}else if("2".equals(type)){//返回復(fù)雜的動態(tài)html
//html?type=2&username=xxx
String username = req.getParameter("username");
pw.println("<p>");
pw.println("歡迎你,"+username);
pw.println("</p>");
}
}
}簡單:
前端顯示:

點擊“查看”:

動態(tài):
前端顯式:

點擊“跳轉(zhuǎn)”:

關(guān)于動態(tài)網(wǎng)頁:在Java的代碼中,寫很多html的代碼
耦合性太強(兩個完全不同的編程語言,放在一起來開發(fā))、維護(hù)性、擴(kuò)展性很差
解決方式:
- 模板技術(shù)
- 這種方式還存在一些問題,進(jìn)一步發(fā)展就有了ajax技術(shù)的產(chǎn)生
二、響應(yīng)一個網(wǎng)頁
返回已有的一個網(wǎng)頁
(1)重定向:
特點:url地址欄會變,發(fā)起兩次請求
原理:
第一次返回301/302/307響應(yīng)狀態(tài)碼,及響應(yīng)頭Location:網(wǎng)頁的地址
第二次:瀏覽器自動的跳轉(zhuǎn)到Location設(shè)置的地址
還是比較常用的:比如登錄成功(其實也可以在js代碼中跳轉(zhuǎn))后,跳轉(zhuǎn)到某個首頁
(2)轉(zhuǎn)發(fā):
特點:url地址欄不變,只有一次請求
原理:當(dāng)次請求Servlet時,由Servlet獲取到轉(zhuǎn)發(fā)路徑的html,把這個路徑的內(nèi)容設(shè)置到響應(yīng)正文
前端代碼:
<h3>重定向到hello.html</h3> <a href="goto?type=1" rel="external nofollow" >跳轉(zhuǎn)</a> <h3>轉(zhuǎn)發(fā)到hello.html</h3> <a href="goto?type=2" rel="external nofollow" >跳轉(zhuǎn)</a>
后端代碼:
@WebServlet("/goto")
public class GoToServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//goto?type=xxx
String type = req.getParameter("type");
if("1".equals(type)){//重定向
// resp.setStatus(301);
// resp.setHeader("Location","hello.html");
//以上代碼可以簡化為sendRedirect
resp.sendRedirect("hello.html");
}else if("2".equals(type)){//轉(zhuǎn)發(fā)
req.getRequestDispatcher("hello.html")
.forward(req,resp);
}
}
}三、返回一個文件
設(shè)置一下Content-Type,然后把文件的二進(jìn)制數(shù)據(jù)放在響應(yīng)正文就可以
前端代碼:
<h3>獲取一個圖片(渲染展示)</h3> <img src="file?type=photo&show=1"> <h3>獲取一個音樂(渲染展示)</h3> <audio src="file?type=music&show=1" controls></audio> <h3>獲取一個圖片(下載)</h3> <a href="file?type=photo&show=0" rel="external nofollow" >下載</a> <h3>獲取一個音樂(下載)</h3> <audio src="file?type=music&show=0" controls></audio>
后端代碼:
@WebServlet("/file")
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//<img src="file?type=photo&show=1">
//獲取響應(yīng)對象的字節(jié)輸出流
OutputStream os = resp.getOutputStream();
//返回的文件類型:1.圖片 2.音樂
String type = req.getParameter("type");
//返回時的操作:1.渲染 2.下載
String show = req.getParameter("show");
File file = null;
byte[] data = null;
//<img src="file?type=photo&show=1">
if("photo".equals(type)){//返回圖片
if("1".equals(show)){
resp.setContentType("image/jpeg");//jpg格式
}else{
//這樣只是沒有設(shè)置下載的文件名,有興趣可以自行擴(kuò)展完成
resp.setContentType("application/octet-stream");
}
file =new File("D:\\java\\servlet-study\\src\\main\\resources\\cui.jpg");
//<audio src="file?type=music&show=1" controls></audio>
}else if("music".equals(type)){//返回音樂
if("1".equals(show)){
resp.setContentType("audio/mp3");//mp3格式
}else{
resp.setContentType("application/octet-stream");
}
file = new File("D:\\java\\servlet-study\\src\\main\\resources\\這世界有那么多人.mp3");
}//其他格式可以自行擴(kuò)展完成
//返回一個文件類型:Content-Length,body
data = Files.readAllBytes(file.toPath());
resp.setContentLength(data.length);//setHeader("Content-Length",xxx)
os.write(data);
}
}問題:圖片、音樂、視頻是靜態(tài)文件,直接放在web應(yīng)用webapp下,就可以直接訪問,那還需要Servlet來返回么?是否多此一舉?
如果文件總的大小非常大,放在web應(yīng)用的webapp下就不合適了:打包就比較費勁,使用Servlet去讀取本地其他地方的文件,來返回,就比較適合
四、返回json數(shù)據(jù)
常用于ajax請求,返回一些數(shù)據(jù),用于動態(tài)的填充網(wǎng)頁
前端代碼:
<body>
<h3>獲取ajax響應(yīng)數(shù)據(jù),動態(tài)生成網(wǎng)頁內(nèi)容</h3>
<button onclick="gen()">試試</button>
<div id="content"></div>
</body>
<script>
function gen(){
let content = document.querySelector("#content");
ajax({
url: "ajax-response",
method: "get",
callback: function(status,resp){
console.log(resp);//resp是一個字符串
//轉(zhuǎn)換為json對象
let array = JSON.parse(resp);
for(json of array){//遍歷
//每一個json對象,創(chuàng)建一個dom來保存信息
let p = document.createElement("p");
p.innerHTML = json.from+" 對 "+json.to+" 說:"+json.info;
content.appendChild(p);
}
}
});
}
function ajax(args){//var ajax = function(){}
let xhr = new XMLHttpRequest();
//設(shè)置回調(diào)函數(shù)
xhr.onreadystatechange = function(){
//4:客戶端接收到響應(yīng)后回調(diào)
if(xhr.readyState == 4){
// 回調(diào)函數(shù)可能需要使用響應(yīng)的內(nèi)容,作為傳入?yún)?shù)
args.callback(xhr.status,xhr.responseText);
}
}
xhr.open(args.method,args.url);
// 如果args中,Content-Type屬性有內(nèi)容,就設(shè)置Content-Type請求頭
if(args.contentType){//js中,除了判斷boolean值,還可以判斷字符串,對象等,有值就為true
xhr.setRequestHeader("Content-Type",args.contentType);
}
//如果args中,設(shè)置了body請求正文,調(diào)用send(body)
if(args.body){
xhr.send(args.body);
}else{//如果沒有設(shè)置,調(diào)用send()
xhr.send();
}
}
</script>后端代碼:
@WebServlet("/ajax-response")
public class AjaxJsonServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Message> messages = new ArrayList<>();
Message m1 = new Message("汪汪","喵喵","我喜歡你");
Message m2 = new Message("喵喵","汪汪","我喜歡你");
messages.add(m1);
messages.add(m2);
ObjectMapper mapper = new ObjectMapper();
//把Java對象,轉(zhuǎn)換為一個json字符串,list和數(shù)組會轉(zhuǎn)換為[],一個對象{成員變量名:值}
String json = mapper.writeValueAsString(messages);
//[{"from":"汪汪","to":"喵喵","info":"我喜歡你"},{"from":"喵喵","to":"汪汪","info":"我喜歡你"}]
System.out.println("轉(zhuǎn)換的json字符串"+json);
//設(shè)置json可以不設(shè)置Content-Length,tomcat會設(shè)置
resp.setContentType("application/json; charset=utf-8");
resp.getWriter().println(json);
}
static class Message{
private String from;//誰
private String to;//對誰
private String info;//說了什么
public Message(String from, String to, String info) {
this.from = from;
this.to = to;
this.info = info;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
}點擊“試試”:


具體過程:

對應(yīng)可以使用的數(shù)據(jù)格式:

到此這篇關(guān)于Java 后端Servlet響應(yīng)httpServletResponse詳解的文章就介紹到這了,更多相關(guān)Servlet 響應(yīng)httpServletResponse內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot+maven多環(huán)境動態(tài)配置及編譯失敗的解決方案(步驟詳解)
這篇文章主要介紹了springboot+maven多環(huán)境動態(tài)配置及編譯失敗的解決方案,本文通過實例圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-11-11
Java基本數(shù)據(jù)類型存儲在JVM中的存儲位置介紹
這篇文章主要介紹了Java基本數(shù)據(jù)類型存儲在JVM中的存儲位置,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
基于Apache組件分析對象池原理的實現(xiàn)案例分析
本文從對象池的一個簡單案例切入,主要分析common-pool2組件關(guān)于:池、工廠、配置、對象管理幾個角色的源碼邏輯,并且參考其在Redis中的實踐,對Apache組件分析對象池原理相關(guān)知識感興趣的朋友一起看看吧2022-04-04
Java中SimpleDateFormat 格式化日期的使用
本文主要介紹了Java中SimpleDateFormat 格式化日期的使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
Java數(shù)據(jù)結(jié)構(gòu)超詳細(xì)分析二叉搜索樹
二叉搜索樹是以一棵二叉樹來組織的。每個節(jié)點是一個對象,包含的屬性有l(wèi)eft,right,p和key,其中,left指向該節(jié)點的左孩子,right指向該節(jié)點的右孩子,p指向該節(jié)點的父節(jié)點,key是它的值2022-03-03
Java9新特性對HTTP2協(xié)議支持與非阻塞HTTP?API
這篇文章主要為大家介紹了Java9新特性對HTTP2協(xié)議的支持與非阻塞HTTP?API,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
java selenium 常見web UI 元素操作及API使用
本文主要介紹java selenium 常見web UI 元素操作,這里幫大家整理了相關(guān)資料并附示例代碼,有需要的小伙伴可以參考下2016-08-08

