一.Request
1.什么是Request
由于Http協(xié)議比較復(fù)雜, 所以在API中提供了 HttpServletRequest (繼承自ServletRequest) 來封裝 Http 請求消息;
2.Request的作用
獲取客戶端的請求信息;
2.1 獲取請求行
@WebServlet("/demo1")
public class ServletDem01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用request對象獲取請求行的信息
//1. 獲取請求的方式(可能會用)
String method = req.getMethod();
System.out.println("method = " + method); // method = GET
//2. 獲取客戶端的ip地址
String remoteAddr = req.getRemoteAddr();
System.out.println("remoteAddr = " + remoteAddr); // 0:0:0:0:0:0:0:1 ipv6地址
//3. 獲取項(xiàng)目部署的路徑
String contextPath = req.getContextPath();
System.out.println("contextPath = " + contextPath); // /rzc
//4. 獲取請求的url: 統(tǒng)一資源定位符 http://localhost:8080/requestDemo/demo01
StringBuffer requestURL = req.getRequestURL();
System.out.println("requestURL = " + requestURL); // http://localhost:8080/rzc/demo1
//5. 獲取請求的uri: 統(tǒng)一資源標(biāo)識符,在url的基礎(chǔ)上省略了服務(wù)器路徑"http://loaclhost:8080"
String requestURI = req.getRequestURI();
System.out.println("requestURI = " + requestURI); // /rzc/demo1
}
}
- getServerPort(); 獲取服務(wù)端的端口
- getQueryString(); 獲取請求參數(shù)(get請求的,URL的?后面的. eg:username=zs&password=123456)
2.2 獲取請求頭
請求頭包含的信息比較多, 需要用的時(shí)候可以通過 getHeader(String name) 函數(shù)來獲取;
- User-Agent: 瀏覽器信息
- Referer: 來自哪個(gè)網(wǎng)站(防盜鏈)
2.3 獲取請求體
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注冊頁面</title>
</head>
<body>
<form action="/rzc/demo3" method="post">
用戶名<input type="text" name="username"><br>
密碼<input type="text" name="password"><br>
性別<input type="radio" name="gender" value="male">男
<input type="radio" name="gender" value="female">女
<br>
興趣愛好
<input type="checkbox" name="hobby" value="basketball">籃球
<input type="checkbox" name="hobby" value="football">足球
<input type="checkbox" name="hobby" value="ppball">乒乓球
<input type="checkbox" name="hobby" value="yumaoball">羽毛球
<br>
<input type="submit" value="注冊">
</form>
</body>
</html>
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 根據(jù)參數(shù)名,獲取一個(gè)參數(shù)值
String username = req.getParameter("username");
System.out.println("username = " + username);
//2. 根據(jù)參數(shù)名,獲取多個(gè)參數(shù)值:比如說注冊時(shí)候的興趣愛好的復(fù)選框
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println("hobby = " + hobby);
}
//3. 獲取所有的請求參數(shù)
//getParameterMap()獲取所有請求參數(shù),請求參數(shù)的參數(shù)名就是map的key,請求參數(shù)的參數(shù)值就是map的value
Map<String, String[]> parameterMap = req.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
String[] values = entry.getValue();
for (String value : values) {
System.out.println("key+\"=\"+value = " + key + "=" + value);
}
}
}
}
使用BeanUtils封裝這些參數(shù)對象
1.需要依賴BeanUtils的jar包
2.Java Bean文件中的屬性名需要和參數(shù)名一一對應(yīng);
BeanUtils.copyProperties(user,parameterMap);
// BeanUtils.populate(user,parameterMap);
2.4 請求轉(zhuǎn)發(fā)
/**
* 1. 請求轉(zhuǎn)發(fā)的效果的跳轉(zhuǎn), 跳轉(zhuǎn)到其他頁面,或者跳轉(zhuǎn)到其它的servlet
* 2. 請求轉(zhuǎn)發(fā)的跳轉(zhuǎn), 只能是跳轉(zhuǎn)到本項(xiàng)目的資源
* 3. 請求轉(zhuǎn)發(fā)的原理是: 服務(wù)器進(jìn)行轉(zhuǎn)發(fā)操作,將這次請求發(fā)給目標(biāo)地址,由服務(wù)器向目標(biāo)地址響應(yīng)資源
*/
@WebServlet("/demo5")
public class ServletDemo5 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 訪問此 Servlet 將跳轉(zhuǎn)到 /register.html
// req.getRequestDispatcher("/register.html").forward(req,resp);
// 訪問此 Servlet 將跳轉(zhuǎn)到訪問 /demo3
req.getRequestDispatcher("/demo3").forward(req,resp);
}
}
2.5 作為域?qū)ο?/h3>
/**
* request 作為域?qū)ο笤诓煌腟ervlet之間進(jìn)行數(shù)據(jù)的共享,它只能在同一次請求中進(jìn)行數(shù)據(jù)共享
* request 域?qū)ο笾挥泻驼埱筠D(zhuǎn)發(fā)一起使用才有意義
*/
@WebServlet("/demo6")
public class ServletDemo6 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("name","ccs");
req.getRequestDispatcher("/demo7").forward(req,resp);
}
}
@WebServlet("/demo7")
public class ServletDemo7 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object name = req.getAttribute("name");
System.out.println("name=="+name);
}
}
二.Response
1.什么是Repsonse
由于Http協(xié)議比較復(fù)雜, 所以在API中提供了 HttpServletResponse (繼承自ServletResponse) 來封裝 Http 響應(yīng)消息;
2.Response的作用
/**
* request 作為域?qū)ο笤诓煌腟ervlet之間進(jìn)行數(shù)據(jù)的共享,它只能在同一次請求中進(jìn)行數(shù)據(jù)共享
* request 域?qū)ο笾挥泻驼埱筠D(zhuǎn)發(fā)一起使用才有意義
*/
@WebServlet("/demo6")
public class ServletDemo6 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("name","ccs");
req.getRequestDispatcher("/demo7").forward(req,resp);
}
}
@WebServlet("/demo7")
public class ServletDemo7 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object name = req.getAttribute("name");
System.out.println("name=="+name);
}
}
由于Http協(xié)議比較復(fù)雜, 所以在API中提供了 HttpServletResponse (繼承自ServletResponse) 來封裝 Http 響應(yīng)消息;
響應(yīng)客戶端的請求
2.1 設(shè)置響應(yīng)行信息
/**
* response 設(shè)置響應(yīng)行的信息
* setStatus設(shè)置響應(yīng)狀態(tài)碼
* 200 響應(yīng)成功
* 302 重定向
* 304 訪問緩存
* 403 沒有權(quán)限訪問
* 404 客戶端錯(cuò)誤
* 500 服務(wù)器錯(cuò)誤
*/
@WebServlet("/demo8")
public class ServletDemo8 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(403);
}
}
2.2 設(shè)置響應(yīng)頭信息以及重定向
/**
* 常用的響應(yīng)頭,需要使用其它的響應(yīng)頭可以去文檔中查找
* Refresh 定時(shí)跳轉(zhuǎn)
* Location 重定向地址
* Content-Disposition 告訴瀏覽器下載
* Content-Type 設(shè)置響應(yīng)內(nèi)容的MiME類型(服務(wù)器告訴瀏覽器內(nèi)容的類型)
*/
@WebServlet("/demo9")
public class ServletDemo9 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Refresh 定時(shí)跳轉(zhuǎn)
// resp.setHeader("Refresh","3,http://www.baidu.com");
// Location 重定向地址
resp.setStatus(302);
resp.setHeader("Location","/rzc/register.html");
// resp.sendRedirect("/rzc/register.html");
// resp.sendRedirect("http://www.baidu.com");
}
}
2.3 設(shè)置響應(yīng)體信息
@WebServlet("/demo9")
public class ServletDemo9 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//給客戶端響應(yīng)一張圖片
//1. 讀取b.jpg圖片,將其轉(zhuǎn)換成字節(jié)輸入流,使用ServletContext
// ServletContext servletContext = getServletContext();
// InputStream is = servletContext.getResourceAsStream("b.jpg");
//
// //2. 使用字節(jié)輸出流,將is中的字節(jié)都輸出到瀏覽器
// ServletOutputStream os = resp.getOutputStream();
//
// /*byte[] buffer = new byte[1024];
// int len = 0;
// while ((len = is.read(buffer)) != -1){
// os.write(buffer,0,len);
// }*/
// IOUtils.copy(is,os);
// os.close();
// is.close();
// 給客戶端響應(yīng)一段字符串
resp.setContentType("text/html;charset=UTF-8");
//要向?yàn)g覽器輸出響應(yīng)體的信息,需要通過流來進(jìn)行操作
//第一種:字符串,輸出文本內(nèi)容
PrintWriter writer = resp.getWriter();
//使用字符流往瀏覽器輸出文本
//1. writer()方法,只能輸出字符串,如果輸出int、float等等類型的話,則會有問題
writer.write("你好世界");
//2. print()方法,可以輸出數(shù)字、字符串
//writer.print(8);
}
}
三.請求轉(zhuǎn)發(fā)與重定向的區(qū)別
1.跳轉(zhuǎn)的發(fā)起者不同
請求轉(zhuǎn)發(fā)的跳轉(zhuǎn)發(fā)起者:是服務(wù)器去重新找到資源響應(yīng)給瀏覽器
重定向的跳轉(zhuǎn)發(fā)起者:是服務(wù)器響應(yīng)給瀏覽器一個(gè)新的地址,兩次都是瀏覽器;
2.瀏覽發(fā)起的請求次數(shù)不同
請求轉(zhuǎn)發(fā):只會請求一次;
重定向:會請求二次;
3.能夠跳轉(zhuǎn)到的資源
請求轉(zhuǎn)發(fā):只能是服務(wù)器本項(xiàng)目中的資源;
重定向:可以是任意地址;
4.地址樣的地址是否發(fā)生改變
請求轉(zhuǎn)發(fā):沒有發(fā)生改變;
重定向:會發(fā)生改變
四.路徑問題
完整路徑, 相對路徑, 絕對路徑; 完整路徑, 是一個(gè)完整的訪問地址, 可以在不同的項(xiàng)目中訪問; 而相對路徑與絕對路徑都是針對相同項(xiàng)目而言的;
1.完整Url地址
url的組成部分:
例如 http://localhost:8080/rzc/jstl/jstl_test01.jsp
- http:// 表示協(xié)議是http協(xié)議
- localhost 表示主機(jī)地址,就是ip地址
- :8080 表示服務(wù)器的端口號 (通過端口號可以找到服務(wù)端程序的進(jìn)程);
- rzc 表示項(xiàng)目的虛擬路徑(部署路徑), 這個(gè)在 idea 中一般為項(xiàng)目名, 可以設(shè)置成不包含這個(gè)路徑的訪問地址;
- jstl/jstl_test01.jsp 表示項(xiàng)目上的具體的動(dòng)態(tài)或靜態(tài)資源;
什么時(shí)候會使用完整的url
瀏覽器地址欄直接訪問;
一個(gè)項(xiàng)目中,訪問另一個(gè)項(xiàng)目中的資源;
2.相對路徑
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路徑相關(guān)測試</title>
</head>
<body>
<h1>hello world....</h1>
<!--
目標(biāo)資源的url: http://localhost:8080/rzc/demo2
當(dāng)前資源的url: http://localhost:8080/rzc/pages/path.html
相對路徑的優(yōu)劣:
1. 優(yōu)勢: 無論部署的項(xiàng)目名怎么改變,我的路徑都不需要改變
2. 劣勢: 如果當(dāng)前資源的位置發(fā)生改變,那么相對路徑就必定要發(fā)生改變
-->
<a href="../demo2">訪問ServletDemo2</a>
</body>
</html>
3.絕對路徑
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>路徑相關(guān)測試</title>
</head>
<body>
<h1>hello world....</h1>
<!--
目標(biāo)資源的url: http://localhost:8080/rzc/demo2
當(dāng)前資源的url: http://localhost:8080/rzc/pages/path.html
絕對路徑: 不是請求轉(zhuǎn)發(fā)的情況, "/項(xiàng)目部署路徑/資源路徑"
1. 優(yōu)勢: 無論當(dāng)前資源的位置怎么發(fā)生改變,絕對路徑都是不變的
2. 劣勢: 如果項(xiàng)目名發(fā)生改變,那么絕對路徑必須改變
-->
<a href="/rzc/demo02">訪問ServletDemo02</a>
</body>
</html>
五.案例代碼
1.文件下載案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下載頁面</title>
</head>
<body>
<a href="/downloadDemo/download?fileName=a.jpg">下載a.jpg</a><br>
<a href="/downloadDemo/download?fileName=b.jpg">下載b.jpg</a><br>
<a href="/downloadDemo/download?fileName=WEB01.zip">下載WEB01.zip</a><br>
<a href="/downloadDemo/download?fileName=美女.jpg">下載美女.jpg</a><br>
<a href="/downloadDemo/download?fileName=霉女.jpg">下載霉女.jpg</a>
</body>
</html>
/**
* 瀏覽器訪問DownloadServlet,如果是圖片直接在瀏覽器上顯示了,現(xiàn)在需要下載這張圖片
* 使用 Content-Disposition 響應(yīng)頭,讓瀏覽器進(jìn)行文件的下載
* 當(dāng)文件名是中文的時(shí)候,瀏覽器下載無法顯示中文 URLEncoder
* file文件應(yīng)該在web目錄下
*/
@WebServlet("/demo10")
public class DownLoadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
//獲取請求參數(shù)fileName的值
String fileName = req.getParameter("fileName");
//讀取對應(yīng)的文件
InputStream is = req.getServletContext().getResourceAsStream("file/"+fileName);
//告訴瀏覽器文件的MIME類型(可以不寫)
String mimeType = getServletContext().getMimeType(fileName);
System.out.println("mimeType = " + mimeType);
resp.setHeader("Content-Type",mimeType);
//使用字節(jié)輸出流,將文件輸出給瀏覽器
ServletOutputStream os = resp.getOutputStream();
//響應(yīng)頭中是無法識別中文的,所以有中文的文件名,在下載的時(shí)候顯示會出現(xiàn)問題
//將文件名進(jìn)行編碼轉(zhuǎn)換,將中文轉(zhuǎn)換成英文
String encodeFileName = URLEncoder.encode(fileName, "UTF-8");
//在輸出內(nèi)容之前,進(jìn)行響應(yīng)頭的設(shè)置,設(shè)置Content-Disposition響應(yīng)頭,讓瀏覽器下載文件
resp.setHeader("Content-Disposition", "attachment;filename=" + encodeFileName);
IOUtils.copy(is, os);
os.close();
is.close();
}
}