河软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技术 | |||||
对授课教师意见建议: 希望老师能带领我们学习实战开发项目,让我们能更好的体会学习。 |