河軟CSDN樂知學院
學員周學習總結
姓名 |
張侃 |
周次 |
10 |
方向 |
Java |
內 容 |
本週學習知識點: 利用session防止表單重複提交 JSP技術
|
||||
本週學習收穫: 利用session防止表單重複提交 session案例-防止表單重複提交 l 不足:但用戶單擊”刷新”,或單擊”後退”再次提交表單,將導致表單重複提交 l 表單頁面由servlet程序生成,servlet爲每次產生的表單頁面分配一個唯一的隨機標識號,並在FORM表單的一個隱藏字段中設置這個標識號,同時在當前用戶的Session域中保存這個標識號。 l 當用戶提交FORM表單時,負責處理表單提交的serlvet得到表單提交的標識號,並與session中存儲的標識號比較,如果相同則處理表單提交,處理完後清除當前用戶的Session域中存儲的標識號。 l 在下列情況下,服務器程序將拒絕用戶提交的表單請求: l 存儲Session域中的表單標識號與表單提交的標識號不同 l 當前用戶的Session中不存在表單標識號 l 用戶提交的表單數據中沒有標識號字段 l 編寫工具類生成表單標識號:TokenProcessor l 一次性驗證碼的主要目的就是爲了限制人們利用工具軟件來暴力猜測密碼。 l 服務器程序接收到表單數據後,首先判斷用戶是否填寫了正確的驗證碼,只有該驗證碼與服務器端保存的驗證碼匹配時,服務器程序纔開始正常的表單處理流程。 l 密碼猜測工具要逐一嘗試每個密碼的前題條件是先輸入正確的驗證碼,而驗證碼是一次性有效的,這樣基本上就阻斷了密碼猜測工具的自動地處理過程。
代碼如下: TokenProcessor.java package com.hbsi.servlet; import java.security.MessageDigest; importjava.security.NoSuchAlgorithmException; import java.util.Random; import sun.misc.BASE64Encoder; public class TokenProcessor { /*1.把構造方法私有化 * 2.創建一個實例對象 * 3.提供一個方法,讓別人能獲取到上面創建的實例對象 * * */ privateTokenProcessor(){ } privatestatic final TokenProcessor instance = new TokenProcessor(); publicstatic TokenProcessor getInstance(){ returninstance; } publicString generateToken(){ inti = new Random().nextInt(); Stringtoken = System.currentTimeMillis()+ i+""; try{ MessageDigestmd =MessageDigest.getInstance("md5"); byte[]md5 = md.digest(token.getBytes()); //base64編碼 BASE64Encoder encoder = new BASE64Encoder(); returnencoder.encode(md5); //returnnew String(md5); }catch (NoSuchAlgorithmException e) { thrownew RuntimeException(e); } } } FormGenerateServlet.java package com.hbsi.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; public class FormGenerateServlet extendsHttpServlet { publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriterout = response.getWriter(); //產生表單號 TokenProcessortp = TokenProcessor.getInstance(); Stringtoken = tp.generateToken(); request.getSession().setAttribute("token",token); out.print("<formaction='/BookHistory/servlet/FormDealServlet' method='post'>"); out.print("<inputtype='hidden' name='token' value='"+token+"'/>"); out.print("用戶名:<input type='text'name='username' />"); out.print("<inputtype='submit' value='提交'/>"); out.print("</form>"); } publicvoid doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException { doGet(request,response); } } FormDealServlet.java package com.hbsi.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpServletResponse; public class FormDealServlet extendsHttpServlet { publicvoid doGet(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException { booleanb = isTokenValidate(request); if(!b){ System.out.println("請不要重複提交表單"); return; } request.getSession().removeAttribute("token"); System.out.println("向數據庫註冊用戶信息。。。"); } privateboolean isTokenValidate(HttpServletRequest request){ Stringclient_token = request.getParameter("token"); if(client_token==null){ returnfalse; } Stringserver_token = (String) request.getSession().getAttribute("token"); if(server_token==null){ returnfalse; } if(!client_token.equals(server_token)){ returnfalse; } returntrue; } publicvoid doPost(HttpServletRequest request, HttpServletResponse response) throwsServletException, IOException { doGet(request,response); } }
servlet文件---------------- package com.hbsi.servlet; import java.io.IOException; import com.hbsi.dao.UserDao; public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) public void doPost(HttpServletRequest request, HttpServletResponse response) doGet(request, response); } html文件-------------------------- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> </head>
JSP技術 起源 l 在很多動態網頁中,絕大部分內容都是固定不變的,只有局部內容需要動態產生和改變。 l 如果使用Servlet程序來輸出只有局部內容需要動態改變的網頁,其中所有的靜態內容也需要程序員用Java程序代碼產生,整個Servlet程序的代碼將非常臃腫,編寫和維護都將非常困難。 l 對大量靜態內容的美工設計和相關HTML語句的編寫,並不是程序員所要做的工作,程序員對此也不一定在行。網頁美工設計和製作人員不懂Java編程,更是無法來完成這樣的工作。 l 爲了彌補Servlet的缺陷,SUN公司在Servlet的基礎上推出了JSP(Java Server Pages)技術作爲解決方案。 l JSP是簡化Servlet編寫的一種技術,它將Java代碼和HTML語句混合在同一個文件中編寫,只對網頁中的要動態產生的內容採用Java代碼來編寫,而對固定不變的靜態內容採用普通靜態HTML頁面的方式編寫。 直觀認識 l JSP頁面是由HTML語句和嵌套在其中的Java代碼組成的一個普通文本文件,JSP頁面的文件擴展名必須爲.jsp。 l 在JSP頁面中編寫的Java代碼需要嵌套在<%和%>中,嵌套在<%和%>之間的Java代碼被稱之爲腳本片段(Scriptlets),沒有嵌套在<%和%>之間的內容被稱之爲JSP的模版元素。 l JSP中的Java代碼可以使用out.println語句將其他Java程序代碼產生的結果字符串輸出給客戶端,也可以使用System.out.println語句將它們打印到命令行窗口。 l JSP文件就像普通的HTML文件一樣,它們可以放置在WEB應用程序中的除了WEB-INF及其子目錄外的其他任何目錄中,JSP頁面的訪問路徑與普通HTML頁面的訪問路徑形式也完全一樣。 什麼是JSP? l JSP全稱是Java Server Pages,它和servle技術一樣,都是SUN公司定義的一種用於開發動態web資源的技術。 l JSP這門技術的最大的特點在於,寫jsp就像在寫html,但它相比html而言,html只能爲用戶提供靜態內容,而Jsp技術允許在頁面中嵌套java代碼,爲用戶提供動態數據。 l 不管是JSP還是Servlet,雖然都可以用於開發動態web資源。但由於這2門技術各自的特點,在長期的軟件實踐中,人們逐漸把servlet作爲web應用中的控制器組件來使用,而把JSP技術作爲數據顯示模板來使用。 l 其原因爲,程序的數據通常要美化後再輸出: • 讓jsp既用java代碼產生動態數據,又做美化會導致頁面難以維護。 • 讓servlet既產生數據,又在裏面嵌套html代碼美化數據,同樣也會導致程序可讀性差,難以維護。 • 因此最好的辦法就是根據這兩門技術的特點,讓它們各自負責各的,servlet只負責響應請求產生數據,並把數據通過轉發技術帶給jsp,數據的顯示jsp來做。 原理 l WEB容器(Servlet引擎)接收到以.jsp爲擴展名的URL的訪問請求時,它將把該訪問請求交給JSP引擎去處理。Tomcat中的JSP引擎就是一個Servlet程序,它負責解釋和執行JSP頁面。 l 每個JSP頁面在第一次被訪問時,JSP引擎將它翻譯成一個Servlet源程序,接着再把這個Servlet源程序編譯成Servlet的class類文件,然後再由WEB容器(Servlet引擎)像調用普通Servlet程序一樣的方式來裝載和解釋執行這個由JSP頁面翻譯成的Servlet程序。 l Tomcat 5.x把爲JSP頁面創建的Servlet源文件和class類文件放置在“<TOMCAT_HOME>\work\Catalina\<主機名>\<應用程序名>\”目錄中,Tomcat將JSP頁面翻譯成的Servlet的包名爲org.apache.jsp.<JSP頁面在WEB應用程序內的目錄名>。 l JSP規範也沒有明確要求JSP中的腳本程序代碼必須採用Java語言,JSP中的腳本程序代碼可以採用Java語言之外的其他腳本語言來編寫,但是,JSP頁面最終必須轉換成Java Servlet程序。 l 可以在WEB應用程序正式發佈之前,將其中的所有JSP頁面預先編譯成Servlet程序。 JSP的執行過程 l JSP的執行過程主要可以分爲以下幾點: • 客戶端發出請求。 • Web容器將JSP轉譯成Servlet源代碼。 • Web容器將產生的源代碼進行編譯。 • Web容器加載編譯後的代碼並執行。 • 把執行結果響應至客戶端。 JSP腳本表達式 l JSP腳本表達式(expression)用於將程序數據輸出到客戶端 語法:<%=變量或表達式 %> 舉例:當前時間:<%= new java.util.Date() %> l JSP引擎在翻譯腳本表達式時,會將程序數據轉成字符串,然後在相應位置用out.print(…)將數據輸給客戶端。 l JSP腳本表達式中的變量或表達式後面不能有分號(;)。 l JSP腳本片斷(scriptlet)用於在JSP頁面中編寫多行Java代碼。語法: <% 多行java代碼 %> l 注意:JSP腳本片斷中只能出現java代碼,不能出現其它模板元素, JSP引擎在翻譯JSP頁面中,會將JSP腳本片斷中的Java代碼將被原封不動地放到Servlet的_jspService方法中。 l JSP腳本片斷中的Java代碼必須嚴格遵循Java語法,例如,每執行語句後面必須用分號(;)結束。 JSP聲明 l JSP頁面中編寫的所有代碼,默認會翻譯到servlet的service方法中,而Jsp聲明中的java代碼被翻譯到_jspService方法的外面。語法: <%! java代碼 %> l 所以,JSP聲明可用於定義JSP頁面轉換成的Servlet程序的靜態代碼塊、成員變量和方法。 l 多個靜態代碼塊、變量和函數可以定義在一個JSP聲明中,也可以分別單獨定義在多個JSP聲明中。 l JSP隱式對象的作用範圍僅限於Servlet的_jspService方法,所以在JSP聲明中不能使用這些隱式對象。 JSP註釋 l JSP註釋的格式: <%-- 註釋信息 --%> l JSP引擎在將JSP頁面翻譯成Servlet程序時,忽略JSP頁面中被註釋的內容。 l 有三種註釋方式 • HTML註釋(輸出註釋):指在客戶端查看源代碼時能看見註釋。例如, <!-- this is an html comment.it will show up int the response. --> • JSP頁註釋(隱藏註釋):指註釋雖然寫在JSP程序中,但不會發送給客戶,因此在客戶端查看源代碼時不能看見註釋。這樣的註釋在JSP編譯時被忽略掉。 <%--this is a JSP comment.it will only be seen in jsp code--%> • Java註釋:只能出現在Java代碼區中,不允許直接出現在頁面中。//單行註釋 /*多行註釋*/ JSP隱式對象 public void _jspService(HttpServletRequest request, HttpServletResponseresponse) throwsjava.io.IOException, ServletException { JspFactory_jspxFactory = null; PageContextpageContext = null; HttpSessionsession= null; ServletContextapplication = null; ServletConfigconfig = null; JspWriterout=null; Objectpage = this; ... ... Throwableexception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request); if(exception != null) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } 九大隱式對象 request response pageContext session application config out page exception out隱式對象 l out隱式對象用於向客戶端發送文本數據。 l out對象是通過調用pageContext對象的getOut方法返回的,其作用和用法與ServletResponse.getWriter方法返回的PrintWriter對象非常相似。 l JSP頁面中的out隱式對象的類型爲JspWriter,JspWriter相當於一種帶緩存功能的PrintWriter,設置JSP頁面的page指令的buffer屬性可以調整它的緩存大小,甚至關閉它的緩存。 l 只有向out對象中寫入了內容,且滿足如下任何一個條件時,out對象纔去調用ServletResponse.getWriter方法,並通過該方法返回的PrintWriter對象將out對象的緩衝區中的內容真正寫入到Servlet引擎提供的緩衝區中: ü 設置page指令的buffer屬性關閉了out對象的緩存功能 ü out對象的緩衝區已滿 ü 整個JSP頁面結束 out隱式對象工作原理 JSP指令 l JSP指令(directive)是爲JSP引擎而設計的,它們並不直接產生任何可見輸出,而只是告訴引擎如何處理JSP頁面中的其餘部分。在JSP2.0規範中共定義了三個指令: • page指令 • Include指令 • taglib指令 JSP指令簡介 l JSP指令的基本語法格式: <%@指令屬性名="值" %> 舉例:<%@ pagecontentType="text/html;charset=gb2312"%> l 如果一個指令有多個屬性,這多個屬性可以寫在一個指令中,也可以分開寫。 例如: <%@page contentType="text/html;charset=gb2312"%> <%@page import="java.util.Date"%> 也可以寫作: <%@page contentType="text/html;charset=gb2312"import="java.util.Date"%> Page指令 l page指令用於定義JSP頁面的各種屬性,無論page指令出現在JSP頁面中的什麼地方,它作用的都是整個JSP頁面,爲了保持程序的可讀性和遵循良好的編程習慣,page指令最好是放在整個JSP頁面的起始位置。 l JSP 2.0規範中定義的page指令的完整語法: <%@ page [language="java" ] [extends="package.class" ] [import="{package.class | package.*},..." ] [session="true | false" ] [buffer="none | 8kb | sizekb" ] [autoFlush="true | false" ] [isThreadSafe="true | false" ] [info="text" ] [errorPage="relative_url" ] [isErrorPage="true | false" ] [contentType="mimeType [ ;charset=characterSet ]"| "text/html ; charset=ISO-8859-1" ] [pageEncoding="characterSet | ISO-8859-1" ] [isELIgnored="true | false" ] %> include指令 l include指令用於引入其它JSP頁面,如果使用include指令引入了其它JSP頁面,那麼JSP引擎將把這兩個JSP翻譯成一個servlet。所以include指令引入通常也稱之爲靜態引入。 l 語法: <%@include file="relativeURL"%> 其中的file屬性用於指定被引入文件的路徑。路徑以“/”開頭,表示代表當前web應用。 l 細節: ü 被引入的文件必須遵循JSP語法。 ü 被引入的文件可以使用任意的擴展名,即使其擴展名是html,JSP引擎也會按照處理jsp頁面的方式處理它裏面的內容,爲了見明知意,JSP規範建議使用.jspf(JSP fragments)作爲靜態引入文件的擴展名。 ü 由於使用include指令將會涉及到2個JSP頁面,並會把2個JSP翻譯成一個servlet,所以這2個JSP頁面的指令不能衝突(除了pageEncoding和導包除外)。
1.[ language="java" ] 主要指定JSP 容器要用什麼語言來編譯JSP 網頁。JSP 1.2 規範中指出,目前只可以使用Java 語言,不過未來不排除增加其他語言,如C、C++、Perl 等等。默認值爲Java語言 2.[ extends="package.class" ] 主要定義此JSP 網頁產生的Servlet 是繼承哪個父類 3.[ import="{package.class | package.*}, ..." ] 定義此JSP 網頁可以使用哪些Java類庫(可以有多個) 4.[ session="true | false" ] 決定此JSP 網頁是否可以使用session 對象。默認值爲true 5.[ buffer="none | 8kb | sizekb" ] 決定輸出流(output stream) 是否有緩衝區。默認值爲8KB 的緩衝區 6.[ autoFlush="true | false" ] 決定輸出流的緩衝區是否要自動清除,緩衝區滿了會產生異常(Exception)。默認值爲true 7.[ isThreadSafe="true | false" ] 告訴JSP 容器,此JSP 網頁是否能同時處理多個請求。默認值爲true,如果此值設爲false,轉義生成的Servlet會實現SingleThreadModel接口。 8.[ info="text" ] 表示此JSP 網頁的相關信息 9.[ errorPage="relative_url" ] 表示如果發生異常錯誤時,網頁會被重新指向指定的URL 10.[ isErrorPage="true | false" ] 表示此JSP Page
是否爲專門處理錯誤和異常的網頁 表示MIME 類型和JSP 網頁的編碼方式,其作用相當於HttpServletResponse接口的setContentType()方法 12.[ pageEncoding="characterSet | ISO-8859-1" ] 用於更改字符編碼 13.[ isELIgnored="true | false" ] 定義在jsp頁面中是否執行或忽略EL表達式。true表示忽略,false表示執行。
|
|||||
學習總結: 繼續學習了session技術防止表單重複提交,學習了JSP技術 |
|||||
對授課教師意見建議: 希望老師能帶領我們學習實戰開發項目,讓我們能更好的體會學習。 |