摘要:什么是對象響應(yīng)由狀態(tài)行實體內(nèi)容消息頭一個空行組成。為什么使用方法能夠正常向瀏覽器輸出中文呢你好呀我是中國這句代碼在轉(zhuǎn)成數(shù)組的時候默認(rèn)查的是編碼,而你好呀我是中國支持編碼,所以可以正常顯示出來。
response、request對象
Tomcat收到客戶端的http請求,會針對每一次請求,分別創(chuàng)建一個代表請求的request對象、和代表響應(yīng)的response對象
既然request對象代表http請求,那么我們獲取瀏覽器提交過來的數(shù)據(jù),找request對象即可。response對象代表http響應(yīng),那么我們向瀏覽器輸出數(shù)據(jù),找response對象即可。
什么是HttpServletResponse對象?http響應(yīng)由狀態(tài)行、實體內(nèi)容、消息頭、一個空行組成。HttpServletResponse對象就封裝了http響應(yīng)的信息。
HttpServletResponse的應(yīng)用 調(diào)用getOutputStream()方法向瀏覽器輸出數(shù)據(jù)調(diào)用getOutputStream()方法向瀏覽器輸出數(shù)據(jù),getOutputStream()方法可以使用print()也可以使用write(),它們有什么區(qū)別呢?我們試驗一下。代碼如下
//獲取到OutputStream流 ServletOutputStream servletOutputStream = response.getOutputStream(); //向瀏覽器輸出數(shù)據(jù) servletOutputStream.print("aaaa");
成功輸出,好像沒什么毛病。
我們試著輸出中文試試
//獲取到OutputStream流 ServletOutputStream servletOutputStream = response.getOutputStream(); //向瀏覽器輸出數(shù)據(jù) servletOutputStream.print("中國!");
出異常了!!!
為什么會出現(xiàn)異常呢?在io中我們學(xué)過,outputStream是輸出二進(jìn)制數(shù)據(jù)的,print()方法接收了一個字符串,print()方法要把“中國”改成二進(jìn)制數(shù)據(jù),Tomcat使用IOS 8859-1編碼對其進(jìn)行轉(zhuǎn)換,“中國”根本對ISO 8859-1編碼不支持。所以出現(xiàn)了異常
我們再看看write()方法,先向瀏覽器輸出英文數(shù)據(jù)
response.getOutputStream().write("aaa".getBytes());
沒有問題
再試試輸出中文數(shù)據(jù)
response.getOutputStream().write("你好呀我是中國".getBytes());
貌似也沒有問題。
為什么使用write()方法能夠正常向瀏覽器輸出中文呢?"你好呀我是中國".getBytes()這句代碼在轉(zhuǎn)成byte[]數(shù)組的時候默認(rèn)查的是gb2312編碼,而"你好呀我是中國"支持gb2312編碼,所以可以正常顯示出來。
但是,程序要實現(xiàn)通用性,應(yīng)該使用的是UTF-8編碼,我們在字符串轉(zhuǎn)換成字節(jié)數(shù)組時指定UTF-8編碼,看看會怎么樣。
response.getOutputStream().write("你好呀我是中國".getBytes("UTF-8"));
好的,成功把它搞成亂碼了!!!
為什么它變成了亂碼呢?原因是這樣的:我在向服務(wù)器輸出的中文是UTF-8編碼的,而瀏覽器采用的是GBK,GBK想顯示UTF-8的中文數(shù)據(jù),不亂碼才怪呢!
既然如此,我將瀏覽器的編碼改成UTF-8試試。
亂碼問題又解決了。可是,每次編寫UTF-8程序時都要去網(wǎng)頁上改編碼格式嗎?這樣明顯不可能的。
既然HTTP響應(yīng)有對瀏覽器說明回送數(shù)據(jù)是什么類型的消息頭,那么HttpServletResponse對象就應(yīng)該有相對應(yīng)的方法告訴瀏覽器回送的數(shù)據(jù)編碼格式是什么
于是乎就去查找Servlet API,找到了設(shè)置消息頭的方法
//設(shè)置頭信息,告訴瀏覽器我回送的數(shù)據(jù)編碼是utf-8的 response.setHeader("Content-Type", "text/html;charset=UTF-8"); response.getOutputStream().write("你好呀我是中國".getBytes("UTF-8"));
瀏覽器在顯示數(shù)據(jù)時,自動把頁面的編碼格式置換成UTF-8,亂碼問題也解決了
另外,除了使用HttpServletResponse對象設(shè)置消息頭的方法,我可以使用html的標(biāo)簽?zāi)M一個http消息頭
下面是代碼:
//獲取到servletOutputStream對象 ServletOutputStream servletOutputStream = response.getOutputStream(); //使用meta標(biāo)簽?zāi)Mhttp消息頭,告訴瀏覽器回送數(shù)據(jù)的編碼和格式 servletOutputStream.write("".getBytes()); servletOutputStream.write("我是中國".getBytes("UTF-8"));
亂碼問題也可以解決
調(diào)用getWriter()方法向瀏覽器輸出數(shù)據(jù)對于getWriter()方法而言,是Writer的子類,那么只能向瀏覽器輸出字符數(shù)據(jù),不能輸出二進(jìn)制數(shù)據(jù)
使用getWriter()方法輸出中文數(shù)據(jù),代碼如下:
//獲取到printWriter對象 PrintWriter printWriter = response.getWriter(); printWriter.write("看完博客點贊!");
喜聞可見的事又出現(xiàn)了,我又出現(xiàn)亂碼了。
為什么出現(xiàn)亂碼了呢?由于Tomcat是外國人的寫,Tomcat默認(rèn)的編碼是ISO 8859-1,當(dāng)我們輸出中文數(shù)據(jù)的時候,Tomcat會依據(jù)ISO 8859-1碼表給我們的數(shù)據(jù)編碼,中文不支持這個碼表呀,所以出現(xiàn)了亂碼
既然如此,我設(shè)置一下編碼不就好了嗎,代碼如下:
//原本是ISO 8859-1的編碼,我設(shè)置成UTF-8 response.setCharacterEncoding("UTF-8"); //獲取到printWriter對象 PrintWriter printWriter = response.getWriter(); printWriter.write("看完博客點贊!");
我再訪問了一下,我的天!看起來更亂了!
為什么亂碼問題還沒有解決?細(xì)心的朋友會發(fā)現(xiàn),我只是在中文轉(zhuǎn)換的時候把碼表設(shè)置成UTF-8,但是瀏覽器未必是使用UTF-8碼表來顯示數(shù)據(jù)的呀
好的,我們來看看瀏覽器的編碼格式,果然,瀏覽器使用GB2312顯示UTF-8的數(shù)據(jù),不亂碼才怪呢
這個問題我們在上面已經(jīng)是有兩種方法解決了【使用標(biāo)簽?zāi)M消息頭、設(shè)置消息頭】,Servlet還提供了一個方法給我們
//設(shè)置瀏覽器用UTF-8編碼顯示數(shù)據(jù) response.setContentType("text/html;charset=UTF-8");
好的,我們再來訪問一下
既然Servlet有那么多方法解決亂碼問題,是不是有一種是最簡便的呢?沒錯!下面這個方法是最簡便的,它不僅設(shè)置瀏覽器用UTF-8顯示數(shù)據(jù),內(nèi)部還把中文轉(zhuǎn)碼的碼表設(shè)置成UTF-8了,也就是說,response.setContentType("text/html;charset=UTF-8");把response.setCharacterEncoding("UTF-8")的事情也干了!
使用getWriter()顯示中文數(shù)據(jù),只需要一個方法就搞掂了!
//設(shè)置瀏覽器用UTF-8編碼顯示數(shù)據(jù), response.setContentType("text/html;charset=UTF-8"); //獲取到printWriter對象 PrintWriter printWriter = response.getWriter(); printWriter.write("看完博客點贊!");實現(xiàn)文件下載
下載資源我們在日常中也很常用,它是怎么做到的呢?要能夠給別人下載,服務(wù)器就應(yīng)該有這個資源
現(xiàn)在我web站點下有一個圖片了!
既然瀏覽器發(fā)送所有的請求都是去找Servlet的話,那么我就寫一個Servlet,當(dāng)別人訪問我這個Servlet的時候,它們就可以下載我這個圖片了!
java的文件上傳下載都是通過io流來完成的,既然要下載圖片,首先要能夠讀取到它
//獲取到資源的路徑 String path = this.getServletContext().getRealPath("/download/1.png"); //讀取資源 FileInputStream fileInputStream = new FileInputStream(path); //獲取到文件名,路徑在電腦上保存是形式的。 String fileName = path.substring(path.lastIndexOf("") + 1);
告訴瀏覽器,我要下載這個文件
//設(shè)置消息頭,告訴瀏覽器,我要下載1.png這個圖片 response.setHeader("Content-Disposition", "attachment; filename="+fileName);
將讀取到的內(nèi)容回送給瀏覽器
//把讀取到的資源寫給瀏覽器 int len = 0; byte[] bytes = new byte[1024]; ServletOutputStream servletOutputStream = response.getOutputStream(); while ((len = fileInputStream.read(bytes)) > 0) { servletOutputStream.write(bytes, 0, len); } //關(guān)閉資源 servletOutputStream.close(); fileInputStream.close();
當(dāng)我訪問時,瀏覽器就提示下載了。
也可以成功打開!
現(xiàn)在問題又有了,如果我文件的名字是中文呢?
我們再訪問一下,發(fā)現(xiàn)名字亂碼了(怎么都是亂碼)
為了解決文件名亂碼,我們要進(jìn)行URL編碼,代碼如下:
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
再次訪問時,文件名亂碼問題就解決了!
實現(xiàn)自動刷新以規(guī)定的時間讓頁面刷新,更新資源
讓瀏覽器實現(xiàn)自動刷新,那肯定又是修改消息頭了。
//每3秒自動刷新網(wǎng)頁一次 response.setHeader("Refresh", "3");
為了更好的看效果,我們加入時間值進(jìn)去
response.getWriter().write("time is :" + System.currentTimeMillis());
每三秒時間值就會發(fā)生變化
學(xué)完上面的,好像沒有什么用,自己上網(wǎng)的時候誰看得見這樣的東西。自動刷新,能夠?qū)崿F(xiàn)頁面的跳轉(zhuǎn)】
我們登陸完網(wǎng)站,很多時候都會看見【登陸成功,3秒后自動跳轉(zhuǎn)....】,其實這個就是用Refresh來完成的。
response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("3秒后跳轉(zhuǎn)頁面....."); //三秒后跳轉(zhuǎn)到index.jsp頁面去,web應(yīng)用的映射路徑我設(shè)置成/,url沒有寫上應(yīng)用名 response.setHeader("Refresh", "3;url="/index.jsp"");
看下效果
設(shè)置緩存瀏覽器本身就存在著緩存機制
當(dāng)我第一次訪問index.jsp時,瀏覽器向服務(wù)器發(fā)了兩次請求【一個是網(wǎng)頁的,一個是圖片的】
當(dāng)我第二次訪問index.jsp的時候,瀏覽器將圖片緩存起來了!圖片不是重新加載的,是從緩存里面取出來的。
像股票類型的網(wǎng)頁是不能取緩存的數(shù)據(jù)的,數(shù)據(jù)都是要不斷更新的。下面我就禁止緩存的功能
//瀏覽器有三消息頭設(shè)置緩存,為了兼容性!將三個消息頭都設(shè)置了 response.setDateHeader("Expires", -1); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma", "no-cache"); //這里為了看效果 PrintWriter printWriter = response.getWriter(); printWriter.print("你好啊" + new Date().toString());
當(dāng)然了,如果頁面有些數(shù)據(jù)不長期更新,你就將它設(shè)置成緩存,這樣可以提高服務(wù)器的性能
實現(xiàn)數(shù)據(jù)壓縮網(wǎng)頁上的信息量是很大的,如果不將數(shù)據(jù)壓縮再回送給瀏覽器,這樣就十分耗費流量
現(xiàn)在我有一篇文章要輸出給瀏覽器
response.setContentType("text/html;charset=UTF-8"); String ss = "fsdfhsdfhuisdhfusdhfuids" + "fsdfdsfsdfsdfdsfdafdsfhsdjfhsdjkfhkjds" + "fdsfjdslkfjsldkfjsdlkfjsdkfsdjkff" + "fsjdfjdsklfjdsklfjkldsfjlksdjflksdjflkds" + "dsjfklsdjflsdjfkldsfkjsdkfjsldkfjsdlfk" + "fdsjlkfjdslkfjsdlkfjlkasjflk"; response.getWriter().write("原來的長度是:"+ss.getBytes().length+""); //輸出給瀏覽器 response.getWriter().write(ss);
訪問一下可以看到,原來的長度是201
壓縮的原理是什么?我們知道getOutputStream()和getWriter()都是直接把數(shù)據(jù)輸出給瀏覽器的。現(xiàn)在我要做的就是讓數(shù)據(jù)不直接輸出給瀏覽器,先讓我壓縮了,再輸出給瀏覽器。java提供了GZIP壓縮類給我們
就讓我們使用GZIP類來對數(shù)據(jù)壓縮吧
//GZIP的構(gòu)造方法需要一個OutputStream子類對象,究竟哪個對象適合,我們看下write()方法 GZIPOutputStream gzipOutputStream = new GZIPOutputStream(); //查看了下API,write()接收的是byte[]類型的。 gzipOutputStream.write();
于是我就在構(gòu)造函數(shù)上傳遞個ByteArrayOutputStream給它
//既然是byte[]類型,那么我就給他一個ByteArrayOutputStream GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new ByteArrayOutputStream());
而用GZIPOutputStream寫數(shù)據(jù)的時候,是把數(shù)據(jù)寫到ByteArrayOutputStream上的,等會還要把數(shù)據(jù)取出來,再寫給瀏覽器,于是就不能以匿名內(nèi)部類的方式給GZIPOutputStream,必須把ByteArrayOutputStream定義出來,
//創(chuàng)建GZIPOutputStream對象,給予它ByteArrayOutputStream ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream); //GZIP對數(shù)據(jù)壓縮,GZIP寫入的數(shù)據(jù)是保存在byteArrayOutputStream上的 gzipOutputStream.write(ss.getBytes()); //gzipOutputStream有緩沖,把緩沖清了,并順便關(guān)閉流 gzipOutputStream.close();
把壓縮后的數(shù)據(jù)取出來,寫給瀏覽器
//將壓縮的數(shù)據(jù)取出來 byte[] bytes = byteArrayOutputStream.toByteArray(); //將壓縮的數(shù)據(jù)寫給瀏覽器 response.getOutputStream().write(bytes);
我們來對比一下壓縮前的大小和壓縮后的大小
數(shù)據(jù)的確是壓縮了,然而,為什么又亂碼了啊?很簡單,既然你壓縮了數(shù)據(jù),你寫給瀏覽器,瀏覽器是不知道你這是壓縮后的數(shù)據(jù),它是以正常的方式打開數(shù)據(jù)的。這當(dāng)然造成亂碼啦!,現(xiàn)在我要告訴瀏覽器我這是壓縮數(shù)據(jù)
//告訴瀏覽器這是gzip壓縮的數(shù)據(jù) response.setHeader("Content-Encoding","gzip"); //再將壓縮的數(shù)據(jù)寫給瀏覽器 response.getOutputStream().write(bytes);
再次訪問一下
生出隨機圖片生成隨機圖片這是非常常見的。在我們登陸的時候經(jīng)常要寫驗證碼,而那些驗證碼是一張圖片,就是通過HttpServletResponse寫給瀏覽器的。
要生成一張圖片,java提供了BufferedImage類供我們使用
//在內(nèi)存中生成一張圖片,寬為80,高為20,類型是RGB BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB); //獲取到這張圖片 Graphics graphics = bufferedImage.getGraphics(); //往圖片設(shè)置顏色和字體 graphics.setColor(Color.BLUE); graphics.setFont(new Font(null, Font.BOLD, 20)); //往圖片上寫數(shù)據(jù),先寫個12345,橫坐標(biāo)是0,縱坐標(biāo)是20【高度】 graphics.drawString("12345", 0, 20);
好的,現(xiàn)在我們在內(nèi)存中創(chuàng)建了一張圖片,并寫上了12345。接著,我們要把圖片寫給瀏覽器了。把圖片寫給瀏覽器,java又提供了圖片流【ImageIO】給我們使用
//要往瀏覽器寫一張圖片,那要告訴瀏覽器回送的類型是一張圖片 response.setHeader("ContentType", "jpeg"); //java提供了圖片流給我們使用,這是一個工具類 //把圖片傳進(jìn)去,類型是jpg,寫給瀏覽器 ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
我們來訪問一下,看下圖片長什么樣
這樣太丑了,我們把背景改成白色看看
//把白色填充整張圖片 graphics.setColor(Color.white); graphics.fillRect(0, 0, 80, 20);
再看看效果,這明顯好看多了
好的,我們的圖片數(shù)字不可能是人工寫的,數(shù)字應(yīng)該是隨機產(chǎn)生的!這個就簡單了。現(xiàn)在我要生成7位的隨機數(shù),生成隨機數(shù)的方法如下
private String makeNum() { Random random = new Random(); //這樣就會生成0-7位的隨機數(shù),現(xiàn)在問題又來了,如果隨機數(shù)不夠7位呢?如果不夠7位,我們加到7位就行了 int anInt = random.nextInt(9999999); //將數(shù)字轉(zhuǎn)成是字符串 String num = String.valueOf(anInt); //判斷位數(shù)有多少個,不夠就加 StringBuffer stringBuffer = new StringBuffer(); for (int i = 0; i < 7 - num.length(); i++) { stringBuffer.append("0"); } return stringBuffer.append(num).toString(); }
如果要生成中文,就找中文映射表即可。
重定向跳轉(zhuǎn)什么是重定向跳轉(zhuǎn)呢?點擊一個超鏈接,通知瀏覽器跳轉(zhuǎn)到另外的一個頁面就叫重定向跳轉(zhuǎn)。是通知瀏覽器去跳轉(zhuǎn),這很重要。頁面之間的跳轉(zhuǎn)有兩種方式:重定向和轉(zhuǎn)發(fā),至于什么時候用重定向,什么用轉(zhuǎn)發(fā),我在講完HttpServletRequest對象的時候會詳細(xì)說明。
我們來使用以下HttpServletResponse對象的重定向
//重定向到index.jsp頁面 response.sendRedirect("/zhongfucheng/index.jsp");
在瀏覽器的地址欄訪問Servlet222
跳轉(zhuǎn)到index.jsp頁面,地址欄發(fā)生了變化
我們再來看看http協(xié)議發(fā)生了什么
從圖上看,我們看到了兩個狀態(tài)碼,一個是302。一個是200。302狀態(tài)碼在http協(xié)議中代表的是臨時重定向。舉個例子:我找紀(jì)律委員說:給我一份請假表,我要回家。紀(jì)律委員告訴我:我這里沒有請假表,你去找輔導(dǎo)員吧。再看回我訪問Sevlet222時:我找Servlet222,Servlet222告訴瀏覽器:我沒有你想要的資源,你要的資源在index.jsp頁面中,你自己去找吧。
很容易看出重定向是通過302狀態(tài)碼和跳轉(zhuǎn)地址實現(xiàn)的。于是乎,我們設(shè)置http消息頭就可以實現(xiàn)重定向跳轉(zhuǎn)
//設(shè)置狀態(tài)碼是302 response.setStatus(302); //HttpServletResponse把常用的狀態(tài)碼封裝成靜態(tài)常量了,所以我們可以使用SC_MOVED_TEMPORARILY代表著302 response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); //跳轉(zhuǎn)的地址是index.jsp頁面 response.setHeader("Location", "/zhongfucheng/index.jsp");
其實sendRedirect()方法就是對setStatus()和setHeader()進(jìn)行封裝,原理就是setStatus()和setHeader()
getWriter和getOutputStream細(xì)節(jié)getWriter()和getOutputStream()兩個方法不能同時調(diào)用。如果同時調(diào)用就會出現(xiàn)異常
Servlet程序向ServletOutputStream或PrintWriter對象中寫入的數(shù)據(jù)將被Servlet引擎從response里面獲取,Servlet引擎將這些數(shù)據(jù)當(dāng)作響應(yīng)消息的正文,然后再與響應(yīng)狀態(tài)行和各響應(yīng)頭組合后輸出到客戶端。
Servlet的serice()方法結(jié)束后【也就是doPost()或者doGet()結(jié)束后】,Servlet引擎將檢查getWriter或getOutputStream方法返回的輸出流對象是否已經(jīng)調(diào)用過close方法,如果沒有,Servlet引擎將調(diào)用close方法關(guān)閉該輸出流對象.
如果文章有錯的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章的同學(xué),可以關(guān)注微信公眾號:Java3y
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/68410.html
摘要:前言由于寫的文章已經(jīng)是有點多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 前言 由于寫的文章已經(jīng)是有點多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 由于更新比較頻繁,因此隔一段時間才會更新目錄導(dǎo)航哦~想要獲取最新原創(chuàng)的技術(shù)文章歡迎關(guān)注我的公眾號:Java3y Java3y文章目錄導(dǎo)航 Java基礎(chǔ) 泛型就這么簡單 注解就這么簡單 Druid數(shù)據(jù)庫連接池...
摘要:對象具有請求域,即完成客戶端的請求之前,該對象一直有效。提交的數(shù)據(jù)量最多不超過。安全性較低但效率比方式高。適合提交數(shù)據(jù)量大,安全性高的用戶信息。除非本次會話的所有頁面都關(guān)閉后再重新訪問某個或者,將會創(chuàng)建新的會話。 JSP 簡介 全名為Java Server Pages,其根本是一個簡化的Servlet設(shè)計,實現(xiàn)了在Java當(dāng)中使用HTML標(biāo)簽。JSP是一種動態(tài)網(wǎng)頁技術(shù)標(biāo)準(zhǔn),也是Java...
摘要:基于的樹狀結(jié)構(gòu),提供在數(shù)據(jù)結(jié)構(gòu)樹中找尋節(jié)點的能力。起初的提出的初衷是將其作為一個通用的介于與間的語法模型。 在你的spiders目錄下創(chuàng)建自己第一個爬蟲項目,我我這兒命名為AiquerSpider.py然后編輯文件 # !/usr/bin/python # -*- coding: UTF-8 -*- import scrapy from scrapy.http import Reque...
閱讀 2465·2021-09-09 09:33
閱讀 2865·2019-08-30 15:56
閱讀 3119·2019-08-30 14:21
閱讀 891·2019-08-30 13:01
閱讀 855·2019-08-26 18:27
閱讀 3584·2019-08-26 13:47
閱讀 3449·2019-08-26 10:26
閱讀 1583·2019-08-23 18:38