一.request和response的介紹
1. request和response的作用
Web服務器收到客戶端的http請求,會針對每一次請求指巡,分別創(chuàng)建一個用于代表請求的request對象锋叨、和代表響應的response對象
request和response對象即然代表請求和響應,那我們要獲取客戶機提交過來的數(shù)據(jù),只需要找request對象就行了奥裸。要向客戶機輸出數(shù)據(jù),只需要找response對象就行了.
2. request和response的體系結構
javax.servlet.Servlet接口中的service方法
public abstract void service(ServletRequest req, ServletResponse res)
javax.servlet.GenericServlet類中的service方法
public abstract void service(ServletRequest req, ServletResponse res)
javax.servlet.http.HttpServlet類中的service方法
在這個類中對service方法進行了重載
public void service(ServletRequest req, ServletResponse res)
protected void service(HttpServletRequest req, HttpServletResponse resp)
二.response
1. response常用api簡單介紹
2. response操作響應行
在http響應行中沪袭,包括協(xié)議,版本號,以及有一個很重要的值湾宙,它叫做響應狀態(tài)碼.響應行中我們主要就是操作這些狀態(tài)碼,它可以有五種類型取值:
常用狀態(tài)碼
200請求成功(其后是對GET和POST請求的應答文檔。)
302所請求的頁面已經(jīng)臨時轉移至新的url冈绊。
304未按預期修改文檔创倔。客戶端有緩沖的文檔并發(fā)出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)焚碌。服務器告訴客戶畦攘,原來緩沖的文檔還可以繼續(xù)使用。
404沒有找到文件或目錄十电。
405請求中指定的方法不被允許
500請求未完成知押。服務器遇到不可預知的情況HttpServletResponse操作狀態(tài)碼API
void setStatus(int sc,String sm)
設置狀態(tài)代碼
void sendError(int sc) throws IOException
設置錯誤狀態(tài)碼
void sendError(int sc,String msg) throws IOException
設置錯誤狀態(tài)碼及信息
3. response操作響應頭
http響應頭的格式是 name:value的格式,如果有多個value值鹃骂,以”,”分開,
例如:
Content-Encoding: gzip
Content-Length: 123
Content-Language: zh-cn
Content-Type: text/html; charset=GB2312
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT
-
HttpServletResponse操作響應頭 API
public void setHeader(String name,String value)
用給定名稱和值設置響應頭台盯。如果已經(jīng)設置了頭,則新值將重寫以前的值public void addHeader(String name, String value)
用給定名稱和值添加響應頭畏线。此方法允許響應頭有多個值public void setIntHeader(String name, int value)
用給定名稱和整數(shù)值設置響應頭静盅。如果已經(jīng)設置了頭,則新值將重寫以前的值寝殴。public void addIntHeader(String name, int value)
用給定名稱和整數(shù)值添加響應頭蒿叠。此方法允許響應頭有多個值明垢。public void setDateHeader(String name, long date)
用給定名稱和日期值設置響應頭。該日期根據(jù)距歷元時間的毫秒數(shù)指定市咽。如果已經(jīng)設置了頭痊银,則新值將重寫以前的值。public void addDateHeader(String name, long date)
用給定名稱和日期值添加響應頭施绎。該日期根據(jù)距歷元時間的毫秒數(shù)指定溯革。此方法允許響應頭有多個值。
案例1:重定向
實現(xiàn):
//1.設置狀態(tài)碼
response.setStatus(302);
//2.設置相應頭--跳轉目錄
response.setHeader(“l(fā)ocation”,”http://localhost/day09/second”);
//response.setHeader(“l(fā)ocation”,”day09/second”);
開發(fā)中我們使用sendRedirect(url);
例如:response.sendRedirect(“day09/second”);
案例2:定時跳轉
在servlet中,我們通過response.setHeader(“refresh”,”3,url=http://localhost/day09/demo2.html”);
response.setHeader("refresh", "3;url=/day09/demo2.html");
在頁面中,我們可以通過
<meta http-equiv="refresh" content="5;url=http://localhost/day09/responseDemo3">
頁面中通過<meta http-equiv=””>方式操作時谷醉,也會將標簽內(nèi)容寫入到http響應中致稀。
4. response操作響應體
http響應正文是我們最終在瀏覽器上看到的結果。
對于HttpServletResponse如果想要操作響應正文俱尼,需要通過response對象獲取到輸出流豺裆,將信息寫回到瀏覽器端.
獲得向客戶端進行數(shù)據(jù)輸出的流對象
OutputStream out = response.getOutputStream();字節(jié)流數(shù)據(jù)輸出
PrintWriter pw = response.getWriter();字符流數(shù)據(jù)輸出
設置輸出數(shù)據(jù)的編碼格式
默認情況下,編碼格式是ISO-8859-1
public void setCharacterEncoding(String charset)
設置發(fā)送到客戶端的響應的字符編碼
public void setContentType(String type)
設置將發(fā)送到客戶端的響應的內(nèi)容類型号显,如果該響應尚未提交臭猜。給定內(nèi)容類型可能包含字符編碼規(guī)范,例如 text/html;charset=UTF-8
操作響應正文注意事項
getOutputStream和getWriter方法分別用于得到輸出二進制數(shù)據(jù)押蚤、輸出文本數(shù)據(jù)的ServletOuputStream蔑歌、Printwriter對象。
getOutputStream和getWriter這兩個方法互相排斥揽碘,調(diào)用了其中的任何一個方法后次屠,就不能再調(diào)用另一方法。
Servlet程序向ServletOutputStream或PrintWriter對象中寫入的數(shù)據(jù)將被Servlet引擎從response里面獲取雳刺,Servlet引擎將這些數(shù)據(jù)當作響應消息的正文劫灶,然后再與響應狀態(tài)行和各響應頭組合后輸出到客戶端。
Serlvet的service方法結束后掖桦,Servlet引擎將檢查getWriter或getOutputStream方法返回的輸出流對象是否已經(jīng)調(diào)用過close方法本昏,如果沒有,Servlet引擎tomcat將調(diào)用close方法關閉該輸出流對象枪汪。調(diào)用close的時候涌穆,會調(diào)用flushBuffer方法.
5. 生成動態(tài)驗證碼
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/驗證碼
public class ImageCodeServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/ 使用java圖形界面技術繪制一張圖片
int charNum = 4;
int width = 30 * 4;
int height = 30;
/ 1. 創(chuàng)建一張內(nèi)存圖片
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
/ 2.獲得繪圖對象
Graphics graphics = bufferedImage.getGraphics();
/ 3、繪制背景顏色
graphics.setColor(Color.YELLOW);
graphics.fillRect(0, 0, width, height);
/ 4雀久、繪制圖片邊框
graphics.setColor(Color.BLUE);
graphics.drawRect(0, 0, width - 1, height - 1);
/ 5宿稀、輸出驗證碼內(nèi)容
graphics.setColor(Color.RED);
graphics.setFont(new Font("宋體", Font.BOLD, 20));
/ 隨機輸出4個字符
Graphics2D graphics2d = (Graphics2D) graphics;
String s = "ABCDEFGHGKLMNPQRSTUVWXYZ23456789";
Random random = new Random();
/session中要用到
String msg="";
int x = 5;
for (int i = 0; i < 4; i++) {
int index = random.nextInt(32);
String content = String.valueOf(s.charAt(index));
msg+=content;
double theta = random.nextInt(45) * Math.PI / 180;
/讓字體扭曲
graphics2d.rotate(theta, x, 18);
graphics2d.drawString(content, x, 18);
graphics2d.rotate(-theta, x, 18);
x += 30;
}
/ 6、繪制干擾線
graphics.setColor(Color.GRAY);
for (int i = 0; i < 5; i++) {
int x1 = random.nextInt(width);
int x2 = random.nextInt(width);
int y1 = random.nextInt(height);
int y2 = random.nextInt(height);
graphics.drawLine(x1, y1, x2, y2);
}
/ 釋放資源
graphics.dispose();
/ 圖片輸出 ImageIO
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
常見的漢字:
String s = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";
三.request
1. request常用api簡單介紹
HttpServletRequest對象用于封裝http請求赖捌,對于http請求它有三部分組成祝沸,http請求行,http請求行及請求正文,下圖描述了關于封裝請求信息方法
2. request操作請求行
public String getMethod()
返回用于發(fā)出此請求的 HTTP 方法的名稱罩锐,例如 GET奉狈、POST
public String getRequestURI()
返回此請求的 URL 的一部分,從協(xié)議名稱一直到 HTTP 請求的第一行中的查詢字符串唯欣。
public String getProtocol()
以 protocol/majorVersion.minorVersion 的形式(例如 HTTP/1.1)返回請求使用的協(xié)議的名稱和版本。
public String getQueryString()
返回包含在請求 URL 中路徑后面的查詢字符串搬味。如果 URL 沒有查詢字符串境氢,則此方法返回 null。
3. request獲取客戶信息
public String getContextPath()
返回請求 URI 指示請求上下文的那一部分碰纬。
public StringBuffer getRequestURL()
重新構造客戶端用于發(fā)出請求的 URL萍聊。返回的 URL 包含一個協(xié)議、服務器名稱悦析、端口號寿桨、服務器路徑,但是不包含查詢字符串參數(shù)强戴。
public String getRemoteAddr()
返回發(fā)送請求的客戶端或最后一個代理的 Internet Protocol (IP) 地址
4. request操作請求頭
public String getHeader(String name)
以 String 的形式返回指定請求頭的值亭螟。
public java.util.Enumeration<E> getHeaders(String name)
以 String 對象的 Enumeration 的形式返回指定請求頭的所有值。
public java.util.Enumeration<E> getHeaderNames()
返回此請求包含的所有頭名稱的枚舉骑歹。如果該請求沒有頭预烙,則此方法返回一個空枚舉。
public int getIntHeader(String name)
以 int 的形式返回指定請求頭的值道媚。如果該請求沒有指定名稱的頭扁掸,則此方法返回 -1。如果無法將頭轉換為整數(shù)最域,則此方法拋出 NumberFormatException谴分。
public long getDateHeader(String name)
以表示 Date 對象的 long 值的形式返回指定請求頭的值
5. request獲取請求參數(shù)
請求參數(shù)是瀏覽器發(fā)送請求時攜帶的信息。
對于請求方式GET與POST镀脂,請求參數(shù)存在位置不同牺蹄。
GET:請求參數(shù)存在于請求的資源路徑中。
POST:請求參數(shù)存在于正文中
public String getParameter(String name)
以 String 形式返回請求參數(shù)的值薄翅,如果該參數(shù)不存在钞馁,則返回 null
public String[] getParameterValues(String name)
返回包含給定請求參數(shù)擁有的所有值的 String 對象數(shù)組,如果該參數(shù)不存在匿刮,則返回 null僧凰。
public java.util.Map<K, V> getParameterMap()
返回此請求的參數(shù)的 java.util.Map。請求參數(shù)是與請求一起發(fā)送的額外信息熟丸。對于 HTTP servlet训措,參數(shù)包含在查詢字符串或發(fā)送的表單數(shù)據(jù)中。
public java.util.Enumeration<E> getParameterNames()
返回包含此請求中所包含參數(shù)的名稱的 String 對象的 Enumeration。如果該請求沒有參數(shù)绩鸣,則此方法返回一個空的 Enumeration怀大。
6. request獲取參數(shù)中文出現(xiàn)亂碼
原因:
漢字在不同的編碼表中的碼值不一樣,那么在使用不同的編碼表進行解碼與編碼操作時呀闻,就會出現(xiàn)亂碼問題.
請求參數(shù)中如果有中文化借,它是以utf-8碼進行了編碼。
Tomcat得到請求參數(shù)是使用iso8859-1進行了解碼捡多,封裝到了request中蓖康。
在通過request獲取請求信息就是亂碼。
解決:
使用iso8859-1進行編碼
在使用utf-8進行解碼
new String(username.getBytes(“iso8859-1”),”utf-8”);
如果請求方式是POST,可以直接使用request.setCharacterEncoding(“utf-8”);就可以解決垒手。
7. request域?qū)ο蟮慕榻B
request對象同時也是一個域?qū)ο笏夂福_發(fā)人員通過request對象在實現(xiàn)轉發(fā)時,把數(shù)據(jù)通過request對象帶給其它web資源處理.
setAttribute方法
getAttribute方法
removeAttribute方法
getAttributeNames方法
request對象提供了一個getRequestDispatcher方法科贬,該方法返回一個RequestDispatcher對象泳梆,調(diào)用這個對象的forward方法可以實現(xiàn)請求轉發(fā),從而共享請求中的數(shù)據(jù)
8. 請求轉發(fā)
請求轉發(fā)可以實現(xiàn)路徑的跳轉操作.
ReqeustDispatcher dispatcher=request.getRequestDispatcher("路徑")
dispatcher.forward(request,response)
請求轉發(fā)和重定向的區(qū)別:
1.請求轉發(fā)是服務器內(nèi)部跳轉榜掌,地址欄不會發(fā)生改變
重定向地址欄會發(fā)生改變优妙。
2.請求轉發(fā),只有一次請求憎账,一次響應.
重定向鳞溉,有兩次請求,兩次響應鼠哥。
3.請求轉發(fā)存在request域熟菲,可以共享數(shù)據(jù).
重定向不存在request域。
4.請求轉發(fā)只能在服務器的內(nèi)部跳轉朴恳,簡單說抄罕,只能訪問本站內(nèi)資源。
重定向可以訪問站外資源于颖,也可以訪問站內(nèi)資源.
5.請求轉發(fā)是由request 發(fā)起的 . request.getRequestDispatcher().forward()
重定向是由response 發(fā)起的 response.sendRedirect();
6.請求轉發(fā)與重定向時路徑寫法不一樣.
重定向要跳轉的路徑是從瀏覽器在次發(fā)起的呆贿,是瀏覽器端路徑,寫法: /工程名/資源
請求轉發(fā)是服務器內(nèi)部跳轉森渐,這時它與瀏覽器無關 寫法:/資源
9. 請求包含
RequestDispatcher.include()方法用于將RequestDispatcher對象封裝的資源內(nèi)容作為當前響應內(nèi)容的一部分包含進來做入,從而實現(xiàn)可編程的服務器端包含功能
被包含的Servlet程序不能改變響應消息的狀態(tài)碼和響應頭,如果它里面存在這樣的語句同衣,這些語句的執(zhí)行結果將被忽略.include在程序執(zhí)行上效果類似forward,但是使用forward只有一個程序可以生成響應竟块,include可以由多個程序一同生成響應 ----- 常用來頁面布局
include()和forward()區(qū)別:
都表示要跳轉到其他資源,不同的是耐齐,如果使用forward跳轉則后面的response輸出則不會執(zhí)行浪秘,而用include
來跳轉蒋情,則include的servlet執(zhí)行完后,再返回到原來的servlet執(zhí)行response的輸出(如果有)耸携。如:
servlet A
RequestDispatcher disp = request.getRequestDispatcher("B");
disp.forward(request, response);
System.out.println("servlet A completed");
PrintWriter pw = response.getWriter();
pw.println("servlet A");
servlet B
PrintWriter pw = response.getWriter();
pw.println("servlet B");
輸出結果:
控制臺:servlet A completed
頁面:servlet B
如果將forward換成include的話棵癣,則結果為:
控制臺:servlet A completed
頁面:servlet B servlet A
PS:如果在servlet B里吧pw給close掉了的話,那servlet A 這里就無法輸出了夺衍,則結果就和第一個一樣狈谊。
四、完成用戶下載功能
技術分析:
- response處理中文亂碼
字節(jié)流:
設置瀏覽器默認打開編碼
response.setHeader("Content-Type", "text/html;charset=UTF-8");
中文轉成字節(jié)數(shù)組編碼
response.getOutputStream().write("王守義".getBytes("UTF-8"));
字符流:
設置response的緩沖區(qū)的編碼
response.setCharacterEncoding("UTF-8");
設置瀏覽器默認打開的編碼.
response.setHeader("Content-Type", "text/html;charset=UTF-8");
response.setContentType("text/html;charset=UTF-8");相當于上面兩句 - 文件下載
一種:超鏈接方式.(不推薦)
<a href=”aa.zip”>下載</a>
<a href=”1.jpg”>下載</a>
二種:手動編碼方式完成文件下載.
設置兩個頭和一個流:
Content-Type:文件MIME的類型.
Content-Disposition:
文件的輸入流:
DownloadServlet核心代碼:
public class DownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//獲取下載文件的名稱
String filename = req.getParameter("name");
//注意中文亂碼:
filename=new String(filename.getBytes("iso8859-1"),"utf-8");
ServletContext context = this.getServletContext();
//文件下載
//1.設置文件的mimeType
String mimeType = context.getMimeType(filename);
resp.setContentType(mimeType);
//2.設置下載的頭信息
//上午的
//response.setHeader("content-disposition", "attchment;filename="+filename);
//常見的瀏覽器將文件名稱使用utf-8 不推薦 不兼容火狐
//response.setHeader("content-disposition", "attchment;filename="+URLEncoder.encode(filename, "utf-8"));
//方式1:通過的方式 通過工具類編碼
//String _filename=DownLoadUtils.getName(request.getHeader("user-agent"), filename);
//response.setHeader("content-disposition", "attachment;filename="+_filename);
//方式2:網(wǎng)絡上的方式 (8成好使)
resp.setHeader("content-disposition", "attachment;filename="+new String(filename.getBytes("gbk"),"iso8859-1"));
//3.對拷流
//獲取輸入流
InputStream is = context.getResourceAsStream("/download/"+filename);
//獲取輸出流
ServletOutputStream os =resp.getOutputStream();
/*int len=-1;
byte[] b=new byte[1024];
while((len=is.read(b))!=-1){
os.write(b, 0, len);
}*/
IOUtils.copy(is, os);
os.close();
is.close();
}
}