課程回顧
XML解析: DOM4J、DOM、SAX、JDOM, getParent() 獲取父節點,再刪除
HTTP協議: 0.9、1.0、1.1 無狀態協議
反射技術: Class類反射入口、獲取類信息、屬性信息、方法信息、構造方法信息、main方法、創建對象(newInstance())、調用方法( invoke )、強制訪問( setAccessible(true) )
動態代理: Proxy.newInstance( 類加載器, 接口數組,InvocationHandler ) MyBatis框架使用動態代理、SpringAOP也是
概述
我們在編寫Servlet的時候,重寫的doGet方法、doPost方法包括兩個參數: HttpServletRequest, HttpServletResponse ;這兩個參數表示的請求和響應對象。請求和響應對象的創建是由Tomcat服務器來實現的,我們開發人員並不需要顯示的創建這兩個對象;可以直接使用。Web服務器收到一個http請求,會針對每個請求創建一個HttpServletRequest和HttpServletResponse對象,從客戶端取數據找HttpServletRequest,向客戶端發送數據就是HttpServletResponse。
特別感謝: CSDN博客——揚俊的小屋做的動畫
HttpServletResponse接口
接口定義
public interface HttpServletResponse extends ServletResponse
所在的包: javax.servlet.http,常見的屬性和方法見文檔。
HttpServletResponse對象代表服務器的響應。該對象可以向客戶端發送三種類型的數據:
- 響應頭:響應的頭部信息
- 響應碼:響應的狀態碼
- 響應體:響應的具體數據
查看HttpServletResponse的API,可以看到這些相關的方法。查看響應的相關信息:
發送響應頭
package com.ujiuye.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/resp2")
public class MyResponse2 extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String str = "對於IO操作來說,使用頻率最高(也是最容易被遺忘)的就是close操作,好在Java規範使用了優雅的Closeable接口,這樣我們只需簡單封裝調用此接口的方法即可。";
System.out.println("原始字節長度:"+str.getBytes().length);
//創建字節數組輸出流,作爲容器,默認長度32個字節
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//創建壓縮輸出流,壓縮,不存儲
GZIPOutputStream zip = new GZIPOutputStream(bos);
//將原始字符串寫到壓縮輸出流
zip.write(str.getBytes());
zip.close();
//把容器轉換成字節數組
byte[] array = bos.toByteArray();
System.out.println("壓縮後的長度:"+array.length);
//操作響應頭
response.setHeader("Content-Encoding", "gzip");
response.setHeader("Content-Length", array.length+"");
response.setHeader("Accept-Range", "bytes");
response.setHeader("Cache-Control", "no-cache");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
執行結果:
發送響應頭控制瀏覽器內容類型
- text/html;charset=utf8 文本或者HTML代碼
- jpeg 圖片格式
- pdf pdf文件
內容類型參考文件: apache-tomcat-8.5.51/conf/web.xml
package com.ujiuye.web;
import java.io.IOException;
import java.io.InputStream;
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;
@WebServlet("/image")
public class MyResponseImage extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//設置響應頭
response.setHeader("Content-Type", "jpeg");
//加載圖片獲取輸入流
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/01.jpeg");
//創建緩衝數組
byte[] b = new byte[1024];
//定義讀取數據長度
int len = 0;
//循環讀取並寫到瀏覽器
ServletOutputStream sos = response.getOutputStream();
while( (len=in.read(b) ) != -1) {
sos.write(b, 0, len);
}
sos.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
http://localhost:8080/chapter13/image
發送響應頭控制瀏覽器禁止緩存
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
}
發送響應頭控制瀏覽器定時刷新
protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
response.setHeader("refresh", "5");//設置refresh響應頭控制瀏覽器每隔5秒鐘刷新一次
//response.setHeader("refresh", "3;url=https://www.baidu.com");//3秒鐘跳轉頁面
}
發送響應碼
Servlet在接收用戶請求並進行業務處理之後要轉向到另一個頁面,譬如成功或失敗頁面,這個頁面跳轉過程稱爲重定向。HttpServletResponse中一般用sendRedirect進行重定向,也就是跳轉到另一個頁面或者Servlet。sendRedirect進行重定向做了下面2件事:
- 設置HTTP響應報頭中的Status爲302
- 設置HTTP響應報頭中的Location值爲指定的URL
HttpServletResponse定義了很多狀態碼的常量(具體可以查看Servlet的API),當需要向客戶端發送響應狀態碼時,可以使用這些常量,避免了直接寫數字,常見的狀態碼對應的常量:
- 狀態碼404對應的常量 SC_NOT_FOUND
- 狀態碼200對應的常量 SC_OK
- 狀態碼500對應的常量 SC_INTERNAL_SERVER_ERROR
用法
HttpServletResponse.sendRedirect("url?參數名1=參數值&參數名2=參數值");
實例
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
/*方法一:使用response.sendRedirect*/
//response.sendRedirect("index.html");
/*方法二:設置響應頭和重定向地址*/
response.setHeader("Location", "index.html");
response.setStatus(HttpServletResponse.SC_FOUND);//設置302狀態碼,等同於response.setStatus(302);
}
發送響應體
通過response對象返回具體數據到瀏覽器是需要的數據傳輸媒介,分爲: 字節流和字符流。
package com.ujiuye.web;
import java.io.IOException;
import java.io.PrintWriter;
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;
@WebServlet("/refresh")
public class MyResponseRefresh extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
/**
* 多學一招:使用HTML語言裏面的標籤來控制瀏覽器行爲,模擬通過設置響應頭控制瀏覽器行爲
* response.setHeader("content-type", "text/html;charset=UTF-8");
*/
String str = "3秒鐘跳轉頁面";
//輸出中文: 字節流
//ServletOutputStream sos = response.getOutputStream();
//sos.write(str.getBytes());
//out.write("使用OutputStream輸出數字:".getBytes("utf-8"));
//out.write( (1+"").getBytes());//字母d,
//字符流
PrintWriter out = response.getWriter();
out.println("字符流:" + str);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
注意:getOutputStream()和getWriter()這兩個方法互相排斥,調用了其中的任何一個方法後,就不能再調用另一方法。
綜合案例:文件下載
編寫Servlet
package com.ujiuye.web;
import java.io.IOException;
import java.io.InputStream;
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;
@WebServlet("/download")
public class MyResponseDownload extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//設置文件下載響應頭
response.setHeader("Content-disposition", "attachment;filename=01.jpeg");
//加載圖片獲取輸入流
InputStream in = getServletContext().getResourceAsStream("/WEB-INF/01.jpeg");
//獲取輸出流
ServletOutputStream out = response.getOutputStream();
//創建緩衝池
byte[] b = new byte[1024];
int len = 0;
while( (len = in.read(b)) != -1 ) {
out.write(b, 0, len);
}
out.close();
in.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
編寫HTML頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="download">文件下載</a>
</body>
</html>
支持中文文件名
package com.ujiuye.web;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
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;
@WebServlet("/download")
public class MyResponseDownload extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//加載圖片獲取輸入流
String realPath = getServletContext().getRealPath("/WEB-INF/美女.jpeg");
String fileName = realPath.substring(realPath.lastIndexOf("/") + 1);
System.out.println("文件名稱:"+fileName);
//設置文件下載響應頭
response.setHeader("Content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "utf-8"));
//InputStream in = getServletContext().getResourceAsStream("/WEB-INF/01.jpeg");
//獲取流
FileInputStream in = new FileInputStream(realPath);
ServletOutputStream out = response.getOutputStream();
//創建緩衝池
byte[] b = new byte[1024];
int len = 0;
while( (len = in.read(b)) != -1 ) {
out.write(b, 0, len);
}
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
綜合案例:圖片驗證碼
package com.ujiuye.web;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/code")
public class MyResponseCode extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 0.設置refresh響應頭控制瀏覽器每隔5秒鐘刷新一次
response.setHeader("refresh", "5");
// 1.在內存中創建一張圖片
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
// 2.得到圖片
// Graphics g = image.getGraphics();
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(Color.WHITE);// 設置圖片的背景色
g.fillRect(0, 0, 80, 20);// 填充背景色
// 3.向圖片上寫數據
g.setColor(Color.BLUE);// 設置圖片上字體的顏色
g.setFont(new Font(null, Font.BOLD, 20));
g.drawString(makeNum(), 0, 20);
// 4.設置響應頭控制瀏覽器瀏覽器以圖片的方式打開
response.setContentType("image/jpeg");// 等同於response.setHeader("Content-Type", "image/jpeg");
// 5.設置響應頭控制瀏覽器不緩存圖片數據
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
// 6.將圖片寫給瀏覽器
ImageIO.write(image, "jpg", response.getOutputStream());
}
/**
* 生成隨機數字
*/
private String makeNum() {
Random random = new Random();
String num = random.nextInt(9999999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 7 - num.length(); i++) {
sb.append("0");
}
num = sb.toString() + num;
return num;
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
訪問地址: http://localhost:8080/chapter13/code
HttpServletRequest接口
接口定義
HttpServletRequest接口的定義
public interface HttpServletRequest extends ServletRequest
父接口: ServletRequest接口的定義, 從定義可以看出ServletRequest是根接口。
public interface ServletRequest
Defines an object to provide client request information to a servlet. The servlet container creates a
ServletRequest
object and passes it as an argument to the servlet’sservice
method.定義一個提供客戶端請求信息到一個Servlet的對象,Servlet容器創建一個ServletRequest對象並作爲一個參數傳遞給Servlet的seivice方法。
A
ServletRequest
object provides data including parameter name and values, attributes, and an input stream. Interfaces that extendServletRequest
can provide additional protocol-specific data (for example, HTTP data is provided byHttpServletRequest
.一個ServletRequest對象提供的數據包括: 參數名稱和參數值、屬性值、輸入流。繼承自ServletRequest接口可以提供額外指定的協議參數,( 例如Http協議 )
實現類: HttpServletRequestWrapper
public class HttpServletRequestWrapper extends ServletRequestWrapper
implements HttpServletRequest
查看請求的相關信息:
獲取請求行信息
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/line")
public class RequestLine extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String scheme = request.getScheme();//獲取協議
String method = request.getMethod(); //請求方法
String url = request.getRequestURL().toString();//請求的URL
String uri = request.getRequestURI();//請求的URI
String param = request.getQueryString();//請求的參數
String protocol = request.getProtocol();//請求的協議
String path = request.getContextPath();//獲取項目名稱
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter();
out.println("scheme:" + scheme + "<br/>");
out.println("method:" + method + "<br/>");
out.println("url:" + url + "<br/>");
out.println("uri:" + uri + "<br/>");
out.println("param:" + param + "<br/>");
out.println("protocol:" + protocol + "<br/>");
out.println("path:" + path + "<br/>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
http://localhost:8080/chapter13/line?username=admin&password=123456
獲取請求頭信息
獲取請求的報文頭信息:
- request.getHeader(“xx”) 根據指定的請求頭獲取值
- request.getHeaders(“xx”)根據指定的請求頭獲取值,值是多個;Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
- request.getHeaderNames()獲取所有的請求頭的名稱,然後就可以根據名稱再獲取值
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/header")
public class RequestHeader extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf8");
PrintWriter out = response.getWriter();
Enumeration<String> en = request.getHeaderNames();//Iterator
while(en.hasMoreElements()) {
String name = en.nextElement();
String value = request.getHeader(name);
out.println(name + "-->" + value + "<br/>");
}
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
執行結果:
獲取請求體信息
獲得客戶機請求參數(客戶端提交的數據)
- getParameter(String)方法**(常用)**
- getParameterValues(String name)方法**(常用)**
- getParameterNames()方法(不常用)
- getParameterMap()方法**(編寫框架時常用)**
註冊頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="download">文件下載</a>
<h1>用戶註冊</h1>
<form name="regForm" action="registerServlet" method="post" id="regForm">
姓名: <input type="text" name="name" id="name"><br>
性別: 男<input type="radio" name="sex" id="radio1" value="男" checked>
女<input type="radio" name="sex" id="radio2" value="女"><br>
愛好:
抽菸<input type="checkbox" name="hobbies" value="抽菸">
喝酒<input type="checkbox" name="hobbies" value="喝酒">
打豆豆<input type="checkbox" name="hobbies" value="打豆豆" checked>
泡妞<input type="checkbox" name="hobbies" value="泡妞"><br/>
簡介: <textarea name="mark" id="" cols="30" rows="10"></textarea><br>
學歷: <select name="education" id="selEdu">
<optgroup label="非正常學歷">
<option value="野雞大學">野雞大學</option>
<option value="家裏蹲大學">家裏蹲大學</option>
<option value="社會大學">社會大學</option>
</optgroup>
<optgroup label="正常學歷">
<option value="初中">初中</option>
<option value="高中" selected="selected">高中</option>
<option value="大學">大學</option>
</optgroup>
</select><br>
<input type="submit" value="提交"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
註冊Servlet
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/registerServlet")
public class RequestBody extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//第一種方法: 根據表單組件名稱獲取值
String name = request.getParameter("name");
String sex = request.getParameter("sex");
String hobbies[] = request.getParameterValues("chk_hobbies");
String mark = request.getParameter("mark");
String edu = request.getParameter("education");
out.println("name:" + name + "<br/>");
out.println("sex:" + sex + "<br/>");
out.println("hobbies:" + Arrays.toString(hobbies) + "<br/>");
out.println("mark:" + mark + "<br/>");
out.println("edu:" + edu + "<br/>");
out.println("<hr/>");
//第二種方法: 如果表單的內容不詳,如何獲取表單數據? Map
Map<String,String[]> map = request.getParameterMap();
for(Map.Entry<String, String[]> entry : map.entrySet()) {
String names = entry.getKey();
String values[] = entry.getValue();
out.println(names + "--->" + Arrays.toString(values).replace("[", "").replace("]", "")+"<br/>");
}
//第三種方法: 先獲取所有的名稱,再跟據名字獲取內容
out.println("<hr/>");
Enumeration<String> en = request.getParameterNames();
while(en.hasMoreElements()) {
String namess = en.nextElement();
if(namess.startsWith("chk_")) {
String [] values = request.getParameterValues(namess);
out.println(namess + "--->" +
Arrays.toString(values).replace("[", "").replace("]", "")+"<br/>");
}else {
String value = request.getParameter(namess);//多選的問題
out.println(namess + "--->" + value+"<br/>");
}
}
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
執行效果
獲取請求客戶端信息
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/remote")
public class RequestRemote extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String addr = request.getRemoteAddr();//客戶端IP地址
String host = request.getRemoteHost();//客戶端主機
int port = request.getRemotePort();//客戶端端口
String user = request.getRemoteUser();//客戶端用戶名稱
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("addr:" + addr+"<br/>");
out.println("host:" + host+"<br/>");
out.println("port:" + port+"<br/>");
out.println("user:" + user+"<br/>");
}
}
獲取本地服務器信息
package com.ujiuye.web2;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/local")
public class RequestLocal extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String addr = request.getLocalAddr();//服務器IP
String host = request.getLocalName();//服務器名稱
int port = request.getLocalPort();//服務器端口
//具體的服務器
String serverName = request.getServerName();
int serverPort = request.getServerPort();
//代表的本地信息,國家、語言
Locale local = request.getLocale();
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("addr:" + addr+"<br/>");
out.println("host:" + host+"<br/>");
out.println("port:" + port+"<br/>");
out.println("local:" + local.getDisplayCountry() + ","+
local.getDisplayLanguage() +"<br/>");
out.println("serverName:" + serverName+"<br/>");
out.println("serverPort:" + serverPort+"<br/>");
}
}