Author:相忠良
Email: ugoood@163.com
起始於:April 18, 2018
最後更新日期:April 22, 2018javascript
聲明:本筆記依據傳智播客方立勳老師 Java Web 的授課視頻內容記錄而成,中間加入了本身的理解。本筆記目的是強化本身學習所用。如有疏漏或不當之處,請在評論區指出。謝謝。
涉及的圖片,文檔寫完後,一次性更新。html
Web服務器收到客戶端的http請求,會針對每一次請求,分別建立一個用於表明請求的 request 對象,和表明響應的 response 對象:java
HttpServletResponse
響應,它封裝了向客戶機 發送數據、發送響應頭和發送響應狀態碼 的方法。例如:web
setStatus(int) setHeader(String, String) getWriter() getOutputStream()
程序已什麼碼錶輸出了,程序就必定要控制瀏覽器以什麼碼錶打開。chrome
1.用 響應頭 的方式控制瀏覽器的碼錶,以下:apache
// servlet 中用 OutputStream 輸出中文的問題 public class ResponseDemo1 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 經過response對象爲瀏覽器指定碼錶 // 程序已什麼碼錶輸出了,程序就必定要控制瀏覽器以什麼碼錶打開 response.setHeader("Content-type", "text/html;charset=UTF-8"); String data = "中國"; OutputStream out = response.getOutputStream(); out.write(data.getBytes("UTF-8")); // 以該碼錶輸出 } }
2.用 html 的<meta>
方式控制瀏覽器的碼錶,此方法 沒有 向瀏覽器發送響應頭。以下(我試驗失敗):windows
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String data = "中國"; OutputStream out = response.getOutputStream(); out.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>" .getBytes()); out.write(data.getBytes("UTF-8")); }
public class ResponseDemo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 設置 response 碼錶 response.setCharacterEncoding("UTF-8"); // 設置瀏覽器應查的碼錶 response.setHeader("content-type", "text/html;charset=UTF-8"); String data = "中國"; PrintWriter out = response.getWriter(); out.write(data); } }
上述代碼設置瀏覽器碼錶,也可這樣寫:response.setContentType("text/html;charset=UTF-8");
,且這句話也修改了 response 的碼錶。設計模式
準備:項目WebRoot
目錄下創建download
目錄,並在該目錄中預先放入1.jpg
和日本妞.jpg
文件。
分別下載這兩個文件的代碼:
注意:若是文件名爲中文,則文件名需通過 url 編碼,下面代碼中有體現:瀏覽器
// 如下載方式打開 public class ResponseDemo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // String path = this.getServletContext().getRealPath("/download/1.jpg"); String path = this.getServletContext().getRealPath("/download/日本妞.jpg"); String filename = path.substring(path.lastIndexOf("\\") + 1); // 發送響應頭,通知瀏覽器如下載方式打開,且文件名是 filename // response.setHeader("content-disposition", "attachment;filename=" // + filename); // 若是文件名爲中文,則文件名需通過 url 編碼 response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); InputStream in = null; OutputStream out = null; try { in = new FileInputStream(path); int len = 0; byte[] buffer = new byte[1024]; out = response.getOutputStream(); while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } } finally { if (in != null) { try { in.close(); } catch (Exception e) { e.printStackTrace(); } } if (out != null) { try { out.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
刷新按鈕做用:無論服務器有沒有緩存,都向服務器發請求。就是把上一次的申請再幹一次。
下面代碼涉及了 控制瀏覽器不留緩存。緩存
// 驗證碼, 谷歌瀏覽器不支持,IE支持本程序 public class ResponseDemo4 extends HttpServlet { // ctrl + shift + x 小寫變大寫 public static final int WIDTH = 120; public static final int HEIGHT = 35; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); // 1. 設置背景色 setBackGround(g); // 2. 設置邊框 setBorder(g); // 3. 畫干擾線 drawRandomLine(g); // 4. 寫隨機數 drawRandomNum((Graphics2D) g); // 5. 圖形寫給瀏覽器 response.setContentType("image/jpeg"); // 發頭控制瀏覽器不要緩存 response.setDateHeader("expries", -1); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); ImageIO.write(image, "jpg", response.getOutputStream()); } private void drawRandomNum(Graphics2D g) { g.setColor(Color.RED); g.setFont(new Font("宋體", Font.BOLD, 20)); // unicode 漢字碼表範圍 [\u4e00-\u9fa5] // 經常使用漢字 String base = "\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"; int x = 5; // 從這開始寫 for (int i = 0; i < 4; i++) { // -30 -- 30度旋轉設定 int degree = new Random().nextInt() % 30; String ch = base.charAt(new Random().nextInt(base.length())) + ""; g.rotate(degree * Math.PI / 180, x, 20); // 設置旋轉弧度 g.drawString(ch, x, 20); g.rotate(-degree * Math.PI / 180, x, 20); x += 30; } } private void drawRandomLine(Graphics g) { g.setColor(Color.GREEN); // 4-5條幹擾線 for (int i = 0; i < 5; i++) { int x1 = new Random().nextInt(WIDTH); int y1 = new Random().nextInt(HEIGHT); int x2 = new Random().nextInt(WIDTH); int y2 = new Random().nextInt(HEIGHT); g.drawLine(x1, y1, x2, y2); } } private void setBorder(Graphics g) { g.setColor(Color.BLUE); g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2); } private void setBackGround(Graphics g) { g.setColor(Color.WHITE); g.fillRect(0, 0, WIDTH, HEIGHT); } }
涉及2文件:src/ResponseDemo4
(上節有了)和WebRoot/register.html
。
register.html代碼以下:
我實踐的結果是,小手 cursor:hand
在 IE 和 Chrome 下都不顯示。
<!DOCTYPE html> <html> <head> <title>register.html</title> <script type="text/javascript"> function changeImage(img) { /* 點圖片,能換一張,而不受緩存影響 */ img.src = img.src + "?" + new Date().getTime(); } </script> </head> <body> <form action=""> 用戶名:<input type="text" name="username"><br /> 密碼:<input type="password" name="password"><br /> 認證碼:<input type="text" name="checkcode"> <!-- 小手點驗證碼 --> <img src="/day06/servlet/ResponseDemo4" onclick="changeImage(this)" alt="換一張" style="cursor:hand"><br /> <input type="submit" value="註冊"> </form> </body> </html>
瀏覽器輸入http://localhost:8080/day06/register.html
查看結果。
1.控制瀏覽器3秒刷新代碼:
public class ResponseDemo5 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("refresh","3"); // 每3秒刷新 String data = new Random().nextInt(10000) + ""; response.getWriter().write(data); } }
2.登陸成功後,跳轉代碼:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 假設這是處理登陸的sevlet // 假設程序運行到此,用戶登陸成功了 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); response.setHeader("refresh", "3;url='/day06/index.jsp'"); response.getWriter().write("恭喜你登陸成功,瀏覽器將在3秒後,跳到首頁,若沒跳,請點<a href=''>超連接</a>"); }
3.登陸成功後,實用的自動跳轉技術: 用到
,想法仍是 servlet 不適合輸出數據,數據在 servlet 中產生後,應傳給一個jsp文件,由jsp修飾格式後,再輸出,代碼以下:
涉及2文件,ResponseDemo5
和WebRoot/message.jsp
,分別以下:
// 控制瀏覽器刷新,跳轉實用代碼 @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 假設這是處理登陸的sevlet // 假設程序運行到此,用戶登陸成功了,要跳轉,實用代碼 // 用 <meta> 模擬 響應頭 讓jsp傳給瀏覽器 // 由於 sevlet 不適合輸出數據,數據需jsp修飾後輸出纔是王道!故而才用<meta>模擬響應頭 String message = "<meta http-equiv='refresh' content='3;url=/day06/index.jsp'>恭喜你登陸成功,瀏覽器將在3秒後,跳到首頁,若沒跳,請點<a href=''>超連接</a>"; this.getServletContext().setAttribute("message", message); // 讓jsp負責輸出數據,需再創建一個message.jsp文件 this.getServletContext().getRequestDispatcher("/message.jsp") .forward(request, response); }
WebRoot/message.jsp
,下面代碼注意把encoding改成UTF-8:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'message.jsp' starting page</title> </head> <body> <!-- 代碼從這開始 --> <% String message = (String) application.getAttribute("message"); out.write(message); %> </body> </html>
本節故事是:控制瀏覽器緩存某個東西1個小時。背景是有些內容幾乎無變化,這就得控制客戶瀏覽器緩存這個內容,不然服務器會累死。
辦法就是 經過服務器向瀏覽器發送控制緩存的響應頭。
實例:客戶訪問index.jsp
,點擊「查看圖書」超連接,而後跳轉到ResponseDemo6
,顯示圖書內容aaaaaaaaaa
。由於圖書內容不怎麼變化,故需用expires
頭控制緩存。
WebRoot/index.jsp
代碼以下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> </head> <body> <a href="/day06/servlet/ResponseDemo6">查看圖書</a> </body> </html>
ResponseDemo6
代碼以下,注意用System.currentTimeMillis()
獲取當前時間,若直接用1000*3600
是不行的:
// 控制緩存 public class ResponseDemo6 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 注意 System.currentTimeMillis() 獲取當前時間 response.setDateHeader("expires", System.currentTimeMillis() + 1000 * 3600); // 緩存1小時 String data = "aaaaaaaaaaaaaa"; response.getWriter().write(data); } }
請求重定向:你管我借錢,我沒有,我讓你找別人。
特色:重定向後,瀏覽器地址欄內容會發生變化,且瀏覽器至關於發送服務器2次請求。
請求重定向能不用盡可能不要用,它加劇了服務器負擔(2次請求)。
何時必須用請求重定向?
實例代碼:
// 實現請求重定向 public class ResponseDemo7 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* response.setStatus(302); response.setHeader("location", "/day06/index.jsp"); */ response.sendRedirect("/day06/index.jsp"); // 這句=上面2句 } }
瀏覽器輸入http://localhost:8080/day06/servlet/ResponseDemo7
查看地址欄變化及結果。
如題,代碼以下:
public class ResponseDemo8 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream(); response.getWriter(); } }
上面代碼運行時要拋異常:
java.lang.IllegalStateException: getOutputStream() has already been called for this response org.apache.catalina.connector.Response.getWriter(Response.java:609) org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:211) cn.wk.response.ResponseDemo8.doGet(ResponseDemo8.java:16) javax.servlet.http.HttpServlet.service(HttpServlet.java:622) javax.servlet.http.HttpServlet.service(HttpServlet.java:729) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
方立勳老師挺有意思,他課堂上說,學生們之後開發時確定會犯上面所說的錯,並報異常,這種異常見不到,不算是合格的開發人員。看到這,我就呵呵了,相忠良確定不會犯這錯誤^^,玩笑話啦。
方老師說,有以下狀況:
public class ResponseDemo8 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream(); this.getServletContext.getRequestDispatcher("/servlet/ResponseDemo9").forward(request, response); // 上面是轉發,不是重定向哦,轉發時客戶瀏覽器地址欄是不變的! } }
public class ResponseDemo9 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter(); } }
轉着轉着就懵逼了,報了那個java.lang.IllegalStateException
異常。
重定向就不會拋這種異常,由於那是2次請求,有2個 response! 轉發是1次請求,只有1個response對象!
經過 response 對象弄出的流,咱們不需關,web容器幫咱們關。但若不是經過 response 弄出的流,咱本身得關,服務器無論!
HttpServletRequest
對象表明客戶端的請求,當客戶端經過 HTTP 協議訪問服務器時,HTTP 請求頭中的全部信息都封裝在這個對象中,開發人員經過這個對象的方法,可或得客戶的這些信息。 request 裏確定有表明客戶請求的請求行,請求頭和請求數據的相關方法。經過 servlet API 查看之。
URI: /news/1.html 它能標識任意資源,URI是爸爸,URL是崽。開發中 URI 用的比 URL 多。
URL: http://www.sina.com/news/1.html 它只能標識互聯網上的資源
例子:
// request 簡單示例 public class RequestDemo1 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(request.getRequestURI()); System.out.println(request.getRequestURL()); System.out.println(request.getQueryString()); System.out.println("---------------------"); System.out.println(request.getRemoteAddr()); // client ip System.out.println(request.getRemoteHost()); // client host name System.out.println(request.getLocalAddr()); // WEB 服務器的 ip System.out.println(request.getLocalName()); // WEB 服務器的主機名 System.out.println(request.getRemotePort()); System.out.println(request.getMethod()); // 返回 GET POST 等 } }
瀏覽器中輸入http://localhost:8080/day06/servlet/RequestDemo1?name=aaa&pass=666
查看結果爲:
/day06/servlet/RequestDemo1 http://localhost:8080/day06/servlet/RequestDemo1 name=aaa&pass=666 --------------------- 0:0:0:0:0:0:0:1 0:0:0:0:0:0:0:1 0:0:0:0:0:0:0:1 0:0:0:0:0:0:0:1 51607 GET
0:0:0:0:0:0:0:1
這個事,訪問時localhost換成127.0.0.1就好了,具體狀況網上查。聽說一般發生在客戶機和服務器在同一臺機器上。感受這個結論不靠譜。
而且,客戶機瀏覽器的 port 也不像方老師所說的隨機,我機器上的表現倒是固定的,但也不徹底固定,不管 chrome 仍是 ie。
// request 獲取頭相關的方法 public class RequestDemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String headValue = request.getHeader("Accept-Encoding"); System.out.println(headValue); System.out.println("---------------------"); Enumeration e = request.getHeaders("Accept-Encoding"); while (e.hasMoreElements()) { String value = (String) e.nextElement(); System.out.println(value); } System.out.println("---------------------"); e = request.getHeaderNames(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); String value = request.getHeader(name); System.out.println(name + " = " + value); } } }
瀏覽器輸入http://localhost:8080/day06/servlet/RequestDemo2
,我機器控制檯的輸出是:
gzip, deflate, br --------------------- gzip, deflate, br --------------------- host = localhost:8080 connection = keep-alive cache-control = max-age=0 upgrade-insecure-requests = 1 user-agent = Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 accept = text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 accept-encoding = gzip, deflate, br accept-language = zh-CN,zh;q=0.9 cookie = _ga=GA1.1.1376610490.1484797437; _gid=GA1.1.1268285374.1524302785
注意:不一樣瀏覽器(IE 和 Chrome)發出的請求頭根本不同,差異還挺大的。
本節案例很重要!
該案例涉及3個文件和2個工具包:RequestDemo2
,WebRoot/test.html
,cn.wk.User
普通java類,commons-beanutils-1.7.0.jar
和commons-logging-1.1.1.jar
工具包。
test.html
代碼:
<!DOCTYPE html> <html> <head> <title>帶數據給RequestDemo2.html</title> <meta name="keywords" content="keyword1,keyword2,keyword3"> <meta name="description" content="this is my page"> <meta name="content-type" content="text/html; charset=UTF-8"> </head> <body> <!-- 帶數據方式1 --> <a href="/day06/servlet/RequestDemo2?username=xxx">點點</a> <!-- 帶數據方式2 --> <form action="/day06/servlet/RequestDemo2" method="post"> 用戶名1:<input type="text" name="username"><br/> 用戶名2:<input type="text" name="username"><br/> 密碼:<input type="text" name="password"><br/> <input type="submit" value="提交"><br/> </form> </body> </html>
cn.wk.User
普通java類代碼:
package cn.wk; public class User { //由於變態的弄了2個username,因此String[],正常不會這樣幹 private String[] username; private String password; public String[] getUsername() { return username; } public void setUsername(String[] username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
RequestDemo2 代碼,裏面有很重要的東西,涉及了 BeanUtils 工具包的使用:
// request 獲取請求頭 和 請求數據 public class RequestDemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("-------獲取數據方式1---------"); String value = request.getParameter("username"); if (value != null && !value.trim().equals("")) { System.out.println(value); } System.out.println("-------獲取數據方式2---------"); String[] values = request.getParameterValues("username"); for (int i = 0; value != null && i < values.length; i++) System.out.println(values[i]); System.out.println("-----最重要的獲取數據方式3 用BeanUtils.populate()----"); // 使用對象 封裝瀏覽器送來的數據 Map<String, String[]> map = request.getParameterMap(); User user = new User(); try { BeanUtils.populate(user, map); // map集合數據填充bean // BeanUtils.copyProperties(dest, orig); bean的拷貝 } catch (Exception e) { e.printStackTrace(); } // 服務器必須以debug方式啓動, 才能觀察斷點 System.out.println(user); // 這打斷點,觀察是否傳入進user對象 } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub doGet(req, resp); } }
瀏覽器輸入http://localhost:8080/day06/test.html
,頁面中輸入數據後提交,再查看控制檯結果。個人test.html
頁面出亂碼了。
下面的2行沒解決個人亂碼問題
eclipse導入項目後HTML文件都是亂碼的(原UTF-8,現GBK)
windows->perferences->General->Content Types->Text->HTML,而後將Default encoding設置爲utf-8便可。
亂碼問題困擾着我。
WebRoot/form.html
代碼以下 (多種 form 數據項類型展現):
<!DOCTYPE html> <html> <head> <title>form.html</title> <meta name="keywords" content="keyword1,keyword2,keyword3"> <meta name="description" content="this is my page"> <meta name="content-type" content="text/html; charset=UTF-8"> </head> <!-- 經常使用的 表單輸入項 類型 --> <body> <form action="/day06/servlet/RequestDemo3" method="post"> 用戶名:<input type="text" name="username"><br/> 密碼:<input type="password" name="password"><br/> 性別: <input type="radio" name="gender" value="male">男 <input type="radio" name="gender" value="female">女<br/> 所在地: <select name="city"> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="chaihe">柴河</option> </select> <br/> 愛好: <input type="checkbox" name="likes" value="sing">唱歌 <input type="checkbox" name="likes" value="dance">跳舞 <input type="checkbox" name="likes" value="basketball">籃球 <input type="checkbox" name="likes" value="football">足球 <br/> 備註:<textarea rows="6" cols="60" name="description"></textarea><br/> 大頭照:<input type="file" name="image"><br/> <!-- 隱藏輸入項 用戶不可見 但表單提交時 一同提交 --> <input type="hidden" name="id" value="12356"> <input type="submit" value="提交"><br/> </form> </body> </html>
RequestDemo3
代碼:
用戶提交的數據必定先檢查後使用!
public class RequestDemo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(request.getParameter("username")); System.out.println(request.getParameter("password")); System.out.println(request.getParameter("gender")); System.out.println(request.getParameter("city")); // 數據必定 先檢查 後使用 String[] likes = request.getParameterValues("likes"); // 遍歷時當心likes爲空 for (int i = 0; likes != null && i < likes.length; i++) { System.out.println(likes[i]); } System.out.println(request.getParameter("description")); // 大頭照涉及文件上傳和下載,在這先不處理 System.out.println(request.getParameter("id")); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
瀏覽器輸入http://localhost:8080/day06/form.html
可能有亂碼,填入數據提交,控制檯查看結果。
涉及2文件,WebRoot/form3.html
和RequestDemo4
,我機器上本實驗作的不成功。
WebRoot/form3.html
以下,2個表單,上面的用post方法,下面的用get方法:
另外一個納悶的事是<meta name="content-type" content="text/html; charset=UTF-8">
對瀏覽器碼錶的設置對我機器不起做用,不知爲啥!
<!DOCTYPE html> <html> <head> <title>form3.html</title> <meta name="keywords" content="keyword1,keyword2,keyword3"> <meta name="description" content="this is my page"> <meta name="content-type" content="text/html; charset=UTF-8"> </head> <body> <form action="/day06/servlet/RequestDemo4" method="post"> 用戶名:<input type="text" name="username"><br/> <input type="submit" value="提交"><br/> </form> <form action="/day06/servlet/RequestDemo4" method="get"> 用戶名:<input type="text" name="username"><br/> <input type="submit" value="提交"><br/> </form> </body> </html>
// post 提交方式 亂碼解決 request.setCharacterEncoding("UTF-8"); //只對post有效 String username = request.getParameter("username"); System.out.println(username);
我機器下面代碼沒法去除亂碼:
// get 提交方式 亂碼解決 String username = request.getParameter("username"); username = new String(username.getBytes("iso-8859-1"), "UTF-8"); System.out.println(username);
超連接提交的中文也只能手工處理(由於也是get提交,按上面get提交亂碼解決方式處理):
<a href="/day06/servlet/RequestDemo4?username=中國">點點</a>
request 域
MVC思想 (model->javabean view -> jsp controller -> servlet)
RequestDemo6 生成數據,用 request 轉發給 /WebRoot/message.jsp 文件顯示:
下面例子簡單,但很是重要。另外,不能轉發兩次!詳細情節看下面代碼:
forward請求轉發的特色:
// 請求轉發,以及使用request域對象把數據帶給轉發資源 public class RequestDemo6 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // MVC思想 (model->javabean view -> jsp controller -> servlet) String data = "aaaaaaa"; req.setAttribute("data", data); // request也可實現轉發 if (true) { req.getRequestDispatcher("/message.jsp").forward(req, resp); return; // return保證了之後不會再次轉發了 } // 但不能再次轉發 // 將拋異常 java.lang.IllegalStateException: Cannot forward after response // has been committed req.getRequestDispatcher("/index.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
/WebRoot/message.jsp 的代碼,裏面涉及了 EL 表達式,jsp中用 EL 表達式取出數據輸出:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'message.jsp' starting page</title> </head> <body> ${data} <!-- EL 表達式 --> <!-- 下面寫法也可,推薦用 EL --> <% String data = (String)request.getAttribute("data"); out.write(data); %> </body> </html>
forward細節:forward 時,會清空response中的數據,以下:
// forward細節: forward時,會清空response中的數據 public class RequestDemo7 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String data = "aaaaaaa"; resp.getWriter().write(data); req.getRequestDispatcher("/index.jsp").forward(req, resp); //會覆蓋上面的resp向瀏覽器送出的信息 } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
如題,代碼以下,本例涉及1個servlet,2個jsp:
public class RequestDemo8 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getRequestDispatcher("/public/head.jsp").include(req, resp); resp.getWriter().write("hahahahaha<br/>"); req.getRequestDispatcher("/public/foot.jsp").include(req, resp); } }
/public/head.jsp
:
<body> head <br> </body>
/public/foot.jsp
:
<body> foot <br> </body>
瀏覽器輸入http://localhost:8080/day06/servlet/RequestDemo8
,輸出結果爲:
head hahahahaha foot
寫地址的原則:
/
開頭;/
就表明當前 web 應用;/
就表明網站;我認爲,第1條有用,其餘2條無所謂。
// 用地址的地方 public class ServletDemo1 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. req.getRequestDispatcher("/").forward(req, resp); // 2. resp.sendRedirect(""); // 3. this.getServletContext().getRealPath(""); // 4. this.getServletContext().getResourceAsStream(""); // 5. /* * <a href="">點點</a> * * <form action="/day06/form1.html"> * * </form> * */ } }
// 防盜鏈 public class RequestDemo9 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 判斷 來訪者從哪一個頁面來的 String referer = request.getHeader("referer"); // 符合盜鏈者條件 if (referer == null || !referer.startsWith("http://localhost")) { response.sendRedirect("/day06/index.jsp"); return; } String data = "鳳姐日記"; response.getWriter().write(data); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }