490 likes | 633 Views
第三讲 JSP技术. 深入 JSP 应用. 本节目标. 标记扩展的概念 标记扩展和 JavaBean 的区别 会使用 JSP+Servlet+JavaBean 开发自己的 Web 应用. 在浏览器显示. HTML. ················· <i>jb-aptech</i> ·················. 根据规范. 2. 1. HTML 规范: http://www.w3.org/TR/html401. 符合规范. 相似. 相似. XML 的 DTD. 解析器 ( 处理器 ). 从 HTML 说起. ?. Qu.:
E N D
第三讲 JSP技术 深入JSP应用
本节目标 • 标记扩展的概念 • 标记扩展和JavaBean的区别 • 会使用JSP+Servlet+JavaBean开发自己的Web应用
在浏览器显示 HTML ················· <i>jb-aptech</i> ················· 根据规范 2 1 HTML规范: http://www.w3.org/TR/html401 符合规范 相似 相似 XML的DTD 解析器(处理器) 从HTML说起 ? Qu.: 可不可以放置自己的“标记”,同时定义自己的“标记库”,设计自己的“处理器”?
标记的概念 功能:在next.jsp中使用 request.getParameter(“image”),把属性“image”的值取出来,也即house.gif <jsp:forward page=”next.jsp”> <jsp:param name=”image” value=”house.gif” /> </jsp:forward> • 假如上面例子使用的JSP标签是我们自己定义的,那么对于该标记而言: • 标记名称:也即jsp:forward,jsp是前缀,forward是后缀,中间用冒号分割 • 标记的属性:page就是jsp:forward的属性,而name、value是jsp:param的属性 • 嵌套:在<jsp:forward>中还有<jsp:param>,前者为父标记,后者为子标记 • 体内容:上面的例子两个标记都没有体内容
标记扩展的概念 • 标记扩展 把“标记”映射到一个或多个Java类,使得用Java类 完成“标记”的功能 • 标记库描述器(Tag Library Descriptor, TLD)文件 是一个XML文档,它描述了包含着一个或多个标 记扩展的标记库
标记扩展的概念 • 标记处理器 实现了标记具体功能的类,是一个JavaBean,它扩展了JSP API提供的javax.servlet.jsp.tagext.TagSupport类 • 在一个要使用标记库任何扩展标记的JSP中,都必须要使用JSP的taglib指令,以引入标记库中的相关标记
为特定需求开发 Java Bean 公共的构建块 应用1 标记扩展 应用2 Java Bean 为特定需求开发 标记扩展和bean的主要区别
标记处理程序 • 执行与自定义标记关联的动作的 Java对象 • 必须实现javax.servlet.jsp.tagext包的Tag或Body Tag接口 • 支持以下方法 • setPageContext(), 设置页面上下文 • setParent(),设置父标记 • doStartTag(),处理开始标记 • doEndTag(), 处理结束标记 • release()
标记处理程序 • BodyTag接口扩展Tag接口,并提供两个附加方法来处理标记主体 • doInitBody() • setBodyContent() • 继承以下两个类来提供这两个接口的实现: • TagSupport(实现Tag接口) • BodyTagSupport(实现BodyTag接口)
标记处理程序 • doStartTag() • 自定义标记开始时调用 • 返回在标记接口中定义的 int 常量的EVAL_BODY_INCLUDE或 SKIP_BODY,以决定是否处理标记的主题部分 • doEndTag() • 在自定义标记结束时调用 • 返回 EVAL_PAGE 或 SKIP_PAGE,以决定是否处理页面的其余部分
自定义标记举例:<examples:hello> <%@ taglib uri="/hello" prefix="examples" %> <html> <head> <title>First custom tag</title> </head> <body> This is static output. <p> <i> <examples:hello></examples:hello> </i> This is static output again. </body> </html> 标记前缀 标记库描述器 hello.jsp 使用标记
自定义标记举例:标记处理器HelloTag 当在JSP中遇到这个标记时,标记处理器必须对从JSP引擎(容器)发来的调用作出反应 package tagext; //放在包tagext中,也即tagext目录下 import java.io.IOException; //向JSP文件输出时,有可能产生IO异常 import java.util.Date; //输出时间时用到的类 import javax.servlet.jsp.*;//和jsp有关的类在该包下 import javax.servlet.jsp.tagext.*; //和标记处理有关的类在该包下 public class HelloTag extends TagSupport //自定义的标记处理器, {// 要继承TagSupport类 ······································
自定义标记举例:标记处理器HelloTag(续) ···································· public int doStartTag() throws JspTagException { return EVAL_BODY_INCLUDE; } ··································· • 在 JSP中的标记:<examples:hello>,相当于开始标记,遇到此标记就调用方法doStartTag() • doStartTag()有两个返回常量:EVAL_BODY_INCLUDE和SKIP_BODY • 返回值EVAL_BODY_INCLUDE表示,JSP引擎要分析标记的体内容和它所拥有的任何的子标记 • 返回值SKIP_BODY表示,JSP引擎应该忽略体内容 • 注意,doStartTag()覆盖了TagSupport的该方法,会抛出JspTagException异常
自定义标记举例:标记处理器HelloTag(续) ········································ public int doEndTag() throws JspTagException { String dateString = new Date().toString(); //当前日期的字符串形式 try { pageContext.getOut().write("Hello world.<br/>"); pageContext.getOut().write("My name is " + getClass().getName() + " and it's " + dateString + "<p/>"); } ································· • 遇到JSP中的结束标记:</examples:hello>,引擎就调用对象的doEndTag()方法 • 其实pageContext对象就是使用hello标记的JSP页面的隐含对象,getout方法返回JspWriter对象 • getClass().getName()返回类名
自定义标记举例:标记处理器HelloTag(续) ·········································· catch (IOException ex) { throw new JspTagException("Fatal error: hello tag could not write to JSP out"); } return EVAL_PAGE; } } • 注意调用JspWriter对象write方法会抛出IOException异常,所以要catch异常 • doEndTag()方法可有两个返回值:EVAL_PAGE和SKIP_PAGE • EVAL_PAGE会让JSP引擎去分析页面的其余内容 • SKIP_PAGE会终止页面分析过程
自定义标记举例:标记库描述器hello.tld • 标记库描述器把标记映射到标记处理器类,并且定义JSP与Hello.Tag类之间的交互方式 • 遵循Sun Microsystems定义的DTD标准的XML文档 • 标记库的所有定义放在<taglib>和</taglib>之间
自定义标记举例:标记库描述器hello.tld(续) • <tlibversion>1.0</tlibversion>表示标记库的版本号码 • <jspversion>1.1</jspversion>表示jsp的版本号 • <shortname>examples</shortname> 是标记的前缀,当在jsp中使用标记时,它的前缀必须是在此处定义的 • <info>Simple example library.</info>是一个对标记的描述
自定义标记举例:标记库描述器hello.tld(续) ······························· <tag> <name>hello</name> <tagclass>tagext.HelloTag</tagclass> <bodycontent>JSP</bodycontent> <info>Simple example</info> </tag> ····································· • 标记库中能够包含任何数量的标记。比如此例子,我们还可以增加另外的<tag>······</tag>标记 • <name>hello</name>表示标记名称,也即标记的后缀
标记扩展目录结构 hello.jsp WEB-INF/ web.xml classes/ tagext/ HelloTag.class tlds/ hello.tld
标记扩展 的web.xml文件 ······································· <taglib> <taglib-uri>/hello</taglib-uri> <taglib-location>/WEB-INF/tlds/hello.tld</taglib-location> </taglib> ································ • 使用标记<taglib>来让服务器知道当在要在JSP引入标记时,从哪儿可以找到TLD • <taglib-uri>/hello</taglib-uri>标记对应于hello.jsp中的该行代码:<%@ taglib uri="/hello" prefix="examples" %> • <taglib-location>···</taglib-location>标记指明标记描述器的位置
hello.jsp <%@ taglib uri=“/hello” prefix=“examples” %> <taglib-uri>/hello</taglib-uri> <taglib-location>/WEB-INF/tlds/hello.tld</taglib-location> web.xml <shortname>example</shortname> ·············· <name>hello</name> <tagclass>tagext.HelloTag</tagclass> ············· hello.tld 实例化 tagext.HelloTag new tagext.HelloTag(); 标记扩展的工作过程 HelloTag 1. 当在jsp中遇到自定义标记时,要找到标记处理器,首先要实例化标记处理器类
<examples:hello></examples:hello> 调用对象的doStartTag()方法 调用对象的doEndTag()方法 标记扩展的工作过程(续) • 以后在JSP中遇到标记库中的标记,调用标记处理器的相应方法
一个综合的例子 • Servlet • Jsp • JavaBean
login.html 功能:要求用户输入用户名和密码 请求 validate.jsp 功能:验证是否合法用户 mypackage.validate 功能:完成验证的javabean 返回结果 合法 不合法 error.jsp 功能:显示错误信息 mypackage.forky 功能:根据用户名转到不同的页面 用户名为jb或aptech 用户名为teacher teacher.jsp 功能:显示“老师们,看到了么,成功了!!同学们,你们看到了么,也成功了!”语句 jb_aptech.jsp 功能:显示“欢迎加入激动人心的ACCP之旅!”等语句 JSP+JavaBean+Servlet案例流程
案例的目录结构 %TOMCAT_HOME%\webapps\ mysample/ login.html validate.jsp jb_aptech.jsp teacher.jsp error.jsp WEB-INF/ web.xml classes/ mypackage/ validate.class forky.class
server.xml文件 • 在server.xml中加上代码: • <Context path="/mysample" docBase="mysample" reloadable="true" /> • 标签Context表示上下文应用环境,path为在浏览器中和在其他文件中使用该应用时要用的应用名 • reloadable标签的值为true表示应用中的任何类文件改变以后,在任何文件中使用的该类都要重新加载,否则不会重新加载
web.xml文件 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd"> <web-app> <welcome-file-list> <welcome-file>login.html</welcome-file> </welcome-file-list> </web-app> <welcome-file>login.html</welcome-file>表示“欢迎”页面,就如同一个网站的index.html,是默认页面一样
login.html文件 <HTML> <HEAD> </HEAD> <BODY> <form name="form1" method="post" action="validate.jsp"> 用户名: <input type="text"name="username" size="15"><br><br> 密码: <input type="password" name="password" size="15"><br><br> <input type="submit" name="Submit" value="确定"> </form> </BODY> </HTML> POST请求到validate.jsp 有两个请求变量post到validate.jsp:username和passward
变量声明部分 <%! boolean isnotlogin = false; %> <% String username = request.getParameter("username"); String password = request.getParameter("password"); if(username==null || password==null) { response.sendRedirect("error.jsp?errmsg=页面值传递错误,或者非法进入该页(在validate.jsp中)"); return; } %> ·································· 取得请求参数的值 如果没有接收到请求参数,就转到错误页面error.jsp,errmsg参数被GET请求发送到error.jsp validate.jsp文件
validate.jsp文件(续) 使用javabean:mypackage.validate ···································· <jsp:useBean id="validatebean" scope="page" class="mypackage.validate" /> <jsp:setProperty name="validatebean" property="username" param="username" /> <jsp:setProperty name="validatebean" property="pwd" param="password" /> </jsp:useBean> ············································ 把请求参数username和password分别传给validatebean的属性:username和pwd
validate.jsp文件(续) uservalidate()是validatebean的方法,是合法用户返回真,是非法用户返回假 ······································ <% islogin = validatebean.uservalidate(); if(!islogin) { response.sendRedirect(“error.jsp?errmsg=用户名或者口令错误!(在validate.jsp中)”); return; } else { session.setAttribute("username",username); %> ········································· 如果是合法用户,则设置session的属性/值
validate.jsp文件(续) 如果是合法用户,就要转到servlet:mypackage.forky,该servlet完成的功能是根据不同的用户名,转到不同的页面 ······································· <jsp:forward page="servlet/mypackage.forky" > <jsp:param name="username" value="<%=username %>" /> </jsp:forward> <% } %> 该段代码在本程序中是没有实际意义的,只作为测试使用
错误处理文件:error.jsp <%@ page language="java" %> <%@ page contentType="text/html;charset=gb2312" %> <% String str=request.getParameter("errmsg"); String errmsg=new String(str.getBytes("ISO-8859-1"),"GBK"); //上面是处理汉字输出的很重要的方法 %> <html> <head> </head> <body> 对不起,您的操作有误。请参考下列提示: <p> <b><%=errmsg %></b> </body> </html>
JavaBean:mypackage.validate package mypackage; public class validate { final String user1="jb"; final String password1="jb"; final String user2="aptech"; final String password2="aptech"; final String user3="teacher"; final String password3="student"; ······································ 在这里直接定义了登陆名和密码,但在实际编程时,登陆名和密码放在数据库里,javabean要通过JDBC访问数据库来验证用户合法性
JavaBean:mypackage.validate(续) ········································ private String username=""; private String pwd=""; public void setUsername(String username) { this.username = username; } public StringgetUsername() { return this.username; } public void setPwd(String password) { this.pwd = password; } public String getPwd() { return this.pwd; } ··········································
JavaBean:mypackage.validate(续) ······································································· public boolean uservalidate() { boolean temp = false; if(username.equals(user1) && pwd.equals(password1)) { temp=true; } else if(username.equals(user2) && pwd.equals(password2)) { temp=true; } else if(username.equals(user3) && pwd.equals(password3)) { temp=true; } else { temp=false; } return temp; } }
servlet:mypackage.forky package mypackage; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class forky extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ //Get session HttpSession session = request.getSession(false);//false 参数禁止创建新会话 if(session==null) { response.sendRedirect(“error.jsp?errmsg=会话已经过期了!。。。”); return; } ·····························································
servlet:mypackage.forky(续) ············································ String username1 = (String)session.getAttribute("username"); if(username1 == null) { return; } //Set MIME type for the response response.setContentType("text/html; charset=GBK"); //Obtain a print writer object PrintWriter out = response.getWriter(); ·············· ·····················································
···················································································· request.setAttribute("username",username2); if(username1.equals("teacher")) { getServletConfig().getServletContext().getRequestDispatcher("/teacher.jsp"). forward(request,response); } else{ getServletConfig().getServletContext().getRequestDispatcher("/jb_aptech.jsp"). forward(request,response); } } } ····································· 把request和response继续发送到定向的文件中 servlet:mypackage.forky(续)
jb_aptech.jsp //如果用户名是jb或者是aptech,则从servlet转入该页面 <%@ page language="java" %> <%@ page contentType="text/html;charset=gb2312" %> <% String username1 = (String)session.getAttribute("username"); if(username1==null) { response.sendRedirect(“error.jsp?errmsg=会话已经过期了。。。”); return; } out.print("<br>"); out.print("欢迎加入激动人心的ACCP之旅!"); out.print("<br>"); out.print("同学们,只要你刻苦、努力的学习,我们相信,你就有美好的前程!"); out.print("<br>"); %>
teacher.jsp //如果用户名是teacher,则从servlet导入该页面 <%@ page language="java" %> <%@ page contentType="text/html;charset=gb2312" %> <% String username1 = (String)session.getAttribute("username"); if(username1==null) { response.sendRedirect(“error.jsp?errmsg=会话已经过期了!”); return; } out.print("哈哈!"); out.print("<br>"); out.print("老师们,看到了么,成功了!!"); out.print("<br>"); out.print("同学们,你们看到了么,也成功了!"); out.print("<br>"); out.print(“成功来之不易,要继续努力哦!"); %>
案例运行 • 启动tomcat,在浏览器中输入http://127.0.0.1:8080/mysample/ ,将会显示登陆页面,如果用户名或密码错误,会出现错误信息 • 如果用户名为jb或aptech、teacher,将显示不同的页面
本讲总结 • JSP标记可以分为三种类型 指令 脚本元素 动作
本节小结 • 标记扩展的概念 把“标记”映射到一个或多个Java类,使得用Java类完成“标记”的功能
本讲总结(续) • 标记处理器,实际上是实现了标记具体功能的类,是一个JavaBean,它扩展了JSP API提供的某个类
本讲总结(续) • 一个标记库描述器TLD文件是一个XML文档,它描述了包含着一个或多个标记扩展的标记库
本节小结(续) • 标记扩展和JavaBean的区别 标记扩展用于公共的构建块 JavaBean为特定需求开发
本节小结(续) • 使用JSP+Servlet+JavaBean开发自己的Web应用 在实际的应用中,用户名信息存储在数据库中, javabean要使用JDBC和数据库相连 在设计Web应用程序时,尽量把“应用逻辑”放在servlet或者javabean中,对数据库的操作应该放在javabean中
下课了。。。 休息一会儿。。。