1月6日——培训第38天


总结的一、二、三在培训日记的第35天…………

四、自定义标签的总结:
1、每个自定义标签都对应一个标签处理类,任何一个标签处理类都必须实现的一个接口是JspTag
2、总的来说,自定义标签可以分为三种,Tag、SimpleTag、Tag File (标签文件),Tag File实际中用的人很少
3、Tag分为三种,
(1)Tag:不处理标签体,只是直接将体的内容直接输出到界面。不能循环处理,它的生命周期doStartTag-》doEndTag
(2)IterationTag:不处理标签体,只是直接将体的内容直接输出到界面。但可以循环处理,它的生命周期:
    doStartTag-->doAfterBody-->doEndTag
    Jsp中提供了一个实现这个接口的实现类叫做TagSupport
(3)BodyTag: 处理标签体,并且可以循环处理。它的生命周期:doStartTag-->doInitBody-->doAfterBody-->doEndTag
   JSP中提供了一个实现这个接口的实现类叫做BodyTagSupport
4、返回值的类型:
SKIP_BODY----------------------doStartTag/doAfterBody
EVAL_BODY_INCLUDE--------------doStartTag
EVAL_BODY_BUFFERED-------------doStartTag (/doAfterBody)
EVAL_BODY_AGAIN----------------doAfterBody (/doStartTag)
SKIP_PAGE----------------------doEndTag
EVAL_PAGE----------------------doEndTag

注意:EVAL_BODY_BUFFERED和EVAL_BODY_AGAIN其实是一样的静态整型常量值,所以括号里面的虽然可以,但是不推荐。

5、SimpleTag标签,它的生命周期
   setJspContext-->setParent-->AttrSetter(所有属性的setter方法)--setJspBody>doTag
这里注意JspFragment代表的是不含有脚本元素的JSP代码片断,tld文件的<body-content>元素必须设置为scriptless或者empty
当值为empty时,不能有标签体!!
 Jsp提供的实现类是SimpleTagSupport

6、Tag File 标签文件(一会儿下面再说)
7、TLD文件(Tag Library Descriptor),一般可以放置在/WEB-INF或者其任意的子目录中,当然放在其他的地方也是没有问题的,
   比如META-INF
8、taglib指令元素,uri和prefix,uri这里可以放置真实地址或者tld文件中的uri的一个虚拟地址


Tag File把标签处理类的代码转换为类似于jsp式的东西,就是对自定义标签的描述;相当于JSP是对Servlet的一种描述

五、表达式语言和JSTL(今天的主要内容)

=======================================================
EL ${}:常量、变量、函数、它们只能是以表达式的形式出现,目的是为了取代脚本表达式
标签做好后可以当作组件使用JUnit来进行测试,但是JSP页面是没有办法进行测试的………………

脚本片断可以用标签或是jsp动作来取代。

表达式语言中,
布尔型、整型、浮点型、字符串型和空值null五种常量类型,有数学操作符、关系操作符、
逻辑操作符、条件操作符、empty操作符、()操作符和[]操作符以及.操作符

保留字有16个,比如gt、or、and之类

出现在EL表达式中的变量,都会被当作存储在某个作用域中的一个属性,从小往大找,即从pageContext、
request、session、application的顺序去找

在JspContext类中有个findAttribute(String name)方法会去顺序找这四个作用域,

${a>b}其实就是先pageContext.findAttribute("a");找a里面存储的属性对象,然后再用相同的方法去找
b里面存储的属性对象。


RequestDispatcher.forward
PageContext.forward
<jsp:forward>
上述三者在jsp页面中都可以使用,都是请求转发


${a=1} 这是不可以的,只能把作用域中的属性值给取出来,不可以给它赋值……
下面介绍EL表达式语言中的.操作符,可以通过点操作符来访问对象的属性,对于自定义的对象,
被访问的属性必须要定义对应的getter方法


   例:
   <%
 Map user = new HashMap();
 user.put("name","Gavin King");
 user.put("age", new Integer(34));
 pageContext.setAttribute("user",user);
   %>

   ${user.name}
   <%=user.get("name")%>
上述两句代码是等价的
--------------------------------------------
EL语言中的11种内置对象,它们和jsp中的9个内置对象没有任何关系,只是名字相近而已

作用域的四个内置对象:
pageScope、requestScope、sessionScope、applicationScope

pageContext也是EL内置对象之一。这个pageContext可以得到所有的Jsp中的内置对象!

param和paramValues也是EL内置对象,还有header和headerValues、Cookie和initParam!
-----------------------------------------------
pageContext有无参的getter方法可以取出作用域!!

如果
 <%
 Map user = new HashMap();
 user.put("name","Gavin King");
 user.put("age", new Integer(34));
 pageContext.setAttribute("user",user);
 request.setAttribute("user",new Integer(36));
 %>
//这时候如果直接使用${user.name}找的肯定是pageContext中的user属性
但是由于Integer中没有无参的getter方法,所以只能使用Integer的getClass方法
${requestScope.user.class} ,指明去请求作用域中去找user属性,
       这会打印出class java.lang.Integer,而不是36……
${requestScope.user} 这就返回的是36了!
${pageContext.request.class}  之所以能这么写是因为PageContext里面有getRequest方法!返回的是ServletRequest
       然后再调用getClass方法!getClass返回的是ServletRequest接口现在的实现类!
       pageContext隐式对象的好处就在于可以调用很多的无参的get方法,而且还可以得到所有的内置对象!!
${pageContext.request.characterEncoding} 这也是可以的(在之前记住要设好请求request的编码)。
${pageContext.request.contextPath} 这也没问题,只要是没有参数的getter方法就可以使用.操作符来访问!
${requestScope.contextPath} 注意这句话和上面的区别,是去请求作用域中找这个同名的属性
JSP:pageContext


${param.user} 是去找同名的参数,比如如果访问这个页面后面加上?user=Gavin ,就会得到Gavin
${paramValues.user[1]} (一般用在复选框中)

${header.accept} //返回accept报头的值

在web.xml中添加如下配置:
<servlet>
 <servlet-name>index</servlet-name>
 <jsp-file>/index.jsp</jsp-file>
 <init-param>
  <param-name>name</param-name>
  <param-value>Gavin</param-value>
 </init-param>
</servlet>
注意上面的是index页面的config隐式对象的参数取的时候<%=%>


<context-param>
 <param-name>name</param-name>
 <param-value>Gavin</param-value>
</context-param>

对于上面来说,${initParam.name} 返回Gavin
注意表达式语言的initParam隐式对象是针对的ServletContext中的initParam参数,也就是web.xml中的<context-param>
定义的初始化参数!

点操作符使用特点:
1、如果点操作符施加在一个javaBean对象上面,则调用JavaBean对象属性的getter方法。
2、如果点操作符施加在一个Map对象上,则调用get方法
3、如果点操作符施加在作用域内置对象上面,则返回存储在这个作用域中的同名属性值
4、如果点操作符施加在pageContext内置对象上,则调用其相应的getter方法
5、如果点操作符施加在参数内置对象param或是paramValues上,则返回同名参数的值!
6、如果点操作符施加在请求报头的内置对象herder或headerValues上,则返回同名报头的值

==================================================

函数:

EL中的函数将映射到一个Java类中的公共而且静态的方法,这种映射是通过TLD文件来完成的

函数语法形式:ns:f(a1,a2……an)

例:新建一个类:
package tag ;

public class ElFunc
{
 public static String showHello(String name)//必须是公共静态的
 {
  return "Hello, " + name + "!" ;
 }
}

TLD文件中的配置
<function>
 <name>showNameEl</name>
 <function-class>tag.ElFunc<function-class/>//指明方法的类
 <function-signature> //指明方法
  java.lang.String showHello(java.lang.String) //这里必须给类的全名
 </function-signature>
</function>

在jsp页面中使用taglib引入tld后,prefix是my
${my:showNameEl("Gavin")}  打印“Hello,Gavin!”

点操作符
1、点操作符施加在JavaBean对象上,则调用JavaBean对象属性的getter方法
2、如果点操作符施加在Map对象上,则调用get方法
3、如果点操作符施加在作用域内置对象上,则返回存储在这个作用域中的同名属性
4、如果点操作符施加在pageConext内置对象上,则调用其相应getter方法。
5、如果点操作符施加在参数内置对象上,则返回同名参数值
6、如果点操作符施加在请求报头内置对象上,则返回同名报头的值
------------------------------------------------------------------------

现在来看一下表达式语言的底层实现机制
javax.servlet.jsp.el包是用来解析EL表达式的
里面有两个接口,两个抽象类,容器Tomcat提供了ExpressionEvaluator和VariableResolver

request.setAttribute("user",new Integer(33));
ExpressionEvaluator ee = pageContext.getExpressionEvaluator();
VariableResolver vr = pageContext.getVariableResolver();
Integer result = (Integer)ee.evaluate("${requestScope.user+10}",Integer.class,vr,null);
//上面那个方法可以去查包里面的具体类,Integer.class是希望返回的具体的类
System.out.println(result); //得到43

其实表达式${requestScope.user+10}就是这么像上面那样解析出来的,这就是EL表达式的底层实现机制的简单介绍。
-------------------------------------------------
下面来作一个标签,达到这样一种效果:
<c:if test="">  //test里面放置一个表达式,检测如果这个值为true的话,就执行标签体,如果不为true,就不执行标签体。
 //要求标签体中放置表达式语言也没有问题
</c:if>

package tag ;
public class ConditionTag extends SimpleTagSupport//它的生命周期只有一个doTag
{
 private boolean test ;
 public void setTest(boolean test)
 {
  this.test = test ;
 }
 public void doTag() throws JspException,IOException
 {
  if(test)
  {
   this.getJspBody().invoke(null); //直接将标签体弄进当前输出流里面去!不用别的代码了
  }
 }
}

tld文件:
<tag>
 <name>if</name>
 <tag-class>tag.ConditionTag</tag-class>
 <body-content>scriptless</body-content>
 <attribute>
  <name>test</name>
  <required>yes</required>
  <rtexprvalue>yes</rtexprvalue>
 </attribute>
</tag>


<c:if test="${user.age>18}">
 <h1>kfdjsljfs</h1>
</c:if>

//这其实就是JSTL核心标签库中的if标签…………

JSTL:JSP Standard Tag Library (JSP标准标签库)

<c:set var="" value="" scope=""/>
作用:将var变量赋予值value,并且存储在作用域scope中去

上述标签如何实现呢?标签处理类的代码如下所示:

package cn.itcast;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class setTag extends SimpleTagSupport{
 private String var ;
 private Integer value ;
 private String scope ;
 public String getScope() {
  return scope;
 }
 public void setScope(String scope) {
  this.scope = scope;
 }
 public Integer getValue() {
  return value;
 }
 public void setValue(Integer value) {
  this.value = value;
 }
 public String getVar() {
  return var;
 }
 public void setVar(String var) {
  this.var = var;
 }
 public void doTag() throws JspException, IOException {
  // TODO Auto-generated method stub
  //super.doTag();
  //System.out.println(this.getJspBody());
  //this.getJspBody().invoke(null);
  
  //PageContext是JspContext的子类!需要强制类型的转换…………
  /*System.out.println("参数名字符串"+var);
  System.out.println("参数值字符串"+value);
  System.out.println("作用域字符串"+scope);*/

  //想办法得到PageContext类,因为它可以和Jsp九大隐式对象通信!
  //而PageContext又正好是JspContext的子类,所以……
  PageContext p = (PageContext)this.getJspContext();
  JspWriter out = this.getJspContext().getOut(); 
  if("session".equals(scope))
  {
   p.getSession().setAttribute(var,value);
  }
  else if("request".equals(scope))
  {
   p.getRequest().setAttribute(var,value);
  }
  else if("application".equals(scope))
  {
   p.getServletContext().setAttribute(var,value);
  }
  else if("page".equals(scope))
  {
   p.setAttribute(var,value);
  }
  //out.println("<%"+scope+".setAttribute(/""+var+"/","+value+")%>");
  //注意:绝对不可以写成上面的样子!!如果写成上面的样子就相当于在查看源文件里面
  //直接嵌入到html里面了,也就是<%%>连同里面的代码会变成html源文件的一部分,完全
  //起不到jsp脚本代码的意义了。
 }

}


tld文件配置:

<tag>
   <name>set</name>
   <tag-class>cn.itcast.setTag</tag-class>
   <body-content>scriptless</body-content>
   <attribute>
    <name>var</name>
    <required>yes</required>
    <rtexprvalue>true</rtexprvalue>
   </attribute>
   <attribute>
    <name>value</name>
    <required>yes</required>
    <rtexprvalue>true</rtexprvalue>
   </attribute>
   <attribute>
    <name>scope</name>
    <required>yes</required>
    <rtexprvalue>true</rtexprvalue>
   </attribute>
  </tag>


  jsp页面:
    <%
     Integer user = new Integer(34);
    %>
    <my:set var="userhaha" value="<%=user%>" scope="session"/>

这样一来就可以在另一个页面通过${sessionScope.userhaha}得到34了。
注意上面的标签里面绝对不可以写成value="${user}"!!因为user一不是作用域中存的属性,
二不是javaBean,三不是Map,所以不行……
=====================================================


中午难得能和田老师一起吃饭,自己都没有想到…………虽然是老师,毕竟也是年轻人,共同话题还是有的,他身上感觉不到
太多的职业人的世故和老成,所以……呵呵,难得赵金良和他住的这么近,竟然没有主动去接触,可惜啊……中国人有的时候
不是很善于和别人沟通交际,这也是……没有办法的事情,换了我恐怕也一样吧,田老师的身体状况并不好,其实不是病什么
的,好像是气血方面有些不足,用中医的话说白了就是“气血不调”,如果一直讲课讲到下午的话可能有的时候声音会变小,而且
有的时候也好像不是很精神,田老师也意识到了这一点,并且在一直吃药,但是……始终不太见好转,我表姐也是差不多的
症状,但是要严重的多,她连多走一走都会有气无力的说不动话,……身体这东西有的时候很难说,对于搞IT的人,可能有的
时候更难说,当老师不容易……


=====================================================
下午介绍JSTL核心标签库……

JSTL就是一套自定义标签,所以需要标签处理类和TLD文件,也就是JAR包和tld文件
标签库共有5个:Core、XML、I18n(处理国际化)、Database、Functions
 前缀名依次为: c     x   fmt                sql      fn
http://java.sun.com/jsp/jstl/core(xml/fmt/sql/functions)

----------------------------------------
core标签:
<c:set>

老师写的set标签处理类:
public class VarSetTag extends SimpleTagSupport
{
 private String var ;
 private Object value ;
 private String scope = "page" ;

 setter、getter方法这里略
 public void doTag() throws JspException,IOException
 {
  //其实JspContext中的setAttribute(String name, Object value, int scope)
  //也可以,注意scope这里是常量,PageContext中定义了一些静态的常量
 
  int scopeValue = PageContext.PAGE_SCOPE //默认是page作用域
  PageContext pageContext = (PageContext)getJspContext();//对于这种方法,这句话是不必要的……
  if("request".equals(scope))
  {
   scopeValue = PageContext.REQUEST_SCOPE;
  }
  else if("session".equals(scope))
  {
   scopeValue = PageContext.SESSION_SCOPE;
  }
  else if("application".equals(scope))
  {
   scopeValue = PageContext.APPLICATION_SCOPE;
  }
  getJspContext().setAttribute(var,value,scopeValue);
 }

}
-------------------------------------

<c:set>两种用途
1、设置变量值:
<c:set var="bookId" value="${param.bookId}" scope="session"/> //如果不写scope的话,默认是存在页面作用域中!
<c:set var="att1">
  <acme:foo>mumbojumbo</acme:foo>
</c:set>
2、设置对象属性:
<c:set target="${cust.address}" property="city" value="${city}"/>
<c:set target="${preferences}" property="color">
    ${param.color}
</c:set>     //target表明一个cust对象中的address是一个javaBean,javaBean里面又个属性叫做city
<c:remove>
<c:remove var="cachedResult" scope="application"/>

例如:
package vo;

//注意下面的两段javaBean的getter和setter方法我都省略了!!
public class Address
{
 private String country ;
 private String city ;
}

public class Customer
{  
 private String name ;
 private Address address = new Address();//这个new Address()如果不写的话就错了!!不写的话就是null!
}

<%@ taglib uri="/WEB-INF/c.tld" prefix="c"%>

//其实target就是设置对象
<jsp:useBean id="cust" class="vo.Customer" scope="session" />
     
     //由于Map是接口,所以必须得用type
<jsp:useBean id="ss" type="java.util.Map" class="java.util.HashMap" scope="session"/>
<c:set target="${ss}" property="name" value="ss"/>
//会在ss类里面存入一个键为name,值为ss的键值对,

<c:set target="${cust.address}" property="city" value="${param.city}" />

<c:set target="${cust}" property="name">
${param.name}
</c:set>


可以${cust.address.city} ,所以没有<c:get>标签

<c:out>标签:
<c:out value="${cust.address.city}">
以前表达式语言在2.0版本以前是不可以在jsp页面直接使用的,这也是为什么<c:out>会
存在的原因,对现在来说,既然可以直接在jsp页面上使用表达式,那么这个<c:out>也没有
必要使用的。
--------------------------------------------
流程控制标签:

条件标记 <c:if>
<c:if test="${user.visitCount == 1}">
      This is your first visit. Welcome to the site!
</c:if>
没有标记体的语法形式:
<c:if test=“${time>16}" var=“result“/>
   必须要指定var属性。当test的内容被计算后,结果将存储在var所指的变量中,JSP页面就可以通过这个变量对结果进行访问了。

根据时间 显示不同的问候语,应该如何使用if标记来实现?

//下面的模拟了if、else if、代码
<c:choose>、<c:when>和<c:otherwise>(注意后两者不可以单独的存在,而是只能够作为前者的标签体出现)
<c:choose>
   <c:when test="${user.category == 'trial'}">
       whenBody1
   </c:when>
   <c:when test="${user.category == 'member'}">
       whenBody2
   </c:when>
   <c:when test="${user.category == 'vip'}">
       whenBody3
   </c:when>
   <c:otherwise>
       otherwiseBody
   </c:otherwise>
</c:choose>

如果要实现if/then/else结果,则就采用如下的形式:
<c:choose>
    <c:when test="${count == 0}">
        No records matched your selection.
    </c:when>
    <c:otherwise>
        ${count} records matched your selection.
    </c:otherwise>
</c:choose>

-------------------------------------
循环结构:

<c:forEach>有两种用法:
1、访问集合类型,例如:
<table>
  <c:forEach var="customer" items="${customers}">
     <tr><td>${customer}</td></tr>
  </c:forEach>
</table>
2、实现一个循环、指定循环的起始、终止及步长,例如:
<c:forEach var="i" begin="100" end="110" step="1">
    ${i}
</c:forEach>。

上述标签模拟了for循环

可以被<c:forEach>元素轮询的集合类型包括:
实现了java.util.Collection的类:List、LinkedList、ArrayList、Vector、Stack和Set。
实现了java.util.Map的类:HashMap、Hashtable、Properties、Provider和Attributes。
对象数组和基本数据类型数组。
实现了java.util.Iterator或java.util.Enumeration的类。


<c:forEach var="i" begin="3" end="10" step="1">//循环变量i会以属性的方式存储在页面的作用域中!
 ${i}<br> 
</c:forEach>
//上面那种循环基本上用处不大

//真正有用的是集合的迭代处理
<%
 ArrayList a = new ArrayList();
 a.add("djkfsa");
 a.add("dfsjklafs");
 pageContext.setAttribute("b",a);
%>

<c:forEach var="name" items="${b}">
 ${name}<br>
</c:forEach>

==========================================================================
使用核心标签库建立留言板:
id                integer         主键、自增
title           varchar(200)
content           text
publish_time    datetime

//注意相应字段要设置中文编码GBK!!
<c:foreach>只能够迭代集合类型,而且这个集合类型必须已经存储在作用域中了!所以应该先到Servlet中去,
让Servlet读出全部的数据然后放到集合里面去,存到request作用域中转发请求给jsp,就可以了。


<body>
 <a href="${pageContext.request.contextPath}/list"></a>//因为上下文路径可能会发生变化,所以需要动态获得。
</body>
//注意list是个Servlet

Servlet代码:
先在server.xml中加上Context字段,里面的内容去Tomcat中拷贝,就像昨天做法一样。别忘了驱动程序要将驱动拷贝到
common/lib中去,这是全局类路径,Tomcat可见,这段Context中的内容相当于一个连接池,是由Tomcat去维护的

//引入javax.naming包
Connection conn = null ;
PreparedStatement pstmt = null ;
ResultSet rs = null ;
int page = 0 ;
int perPage = 10 ;

try
{
 page = Integer.parseInt(request.getParameter("page"));
 perPage = Integer.parseInt(request.getParameter("perPage"));
}
catch(NumberFormatException e1)
{
 page = 0 ;    //第一次访问页面的时候request中肯定什么属性也没有设置,所以会出现异常
 perPage = 10 ;
}
try
{
 Context ctx = new InitialContext();
 DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/data");
 conn = ds.getConnection();

 pstmt = conn.prepareStatement(select * from article limit ?,?);
 pstmt.setInt(1,page*perPage);
 pstmt.setInt(2,perPage);

 
 
 rs = pstmt.executeQuery();

 ArrayList articles = new ArrayList();
 while(rs.next())
 {
  Map map = new HashMap();
  map.put("id",new Integer(rs.getInt(1)));
  map.put("title",rs.getString(2));
  map.put("content",rs.getString(3));
  map.put("time",rs.getTimestamp(4));//SimpleDateFormat可以转换为想要的时间日期格式
  articles.add(map);
 }
 
 pstmt = conn.prepareStatement("select count(*) from articles");
 rs = pstmt.executeQuery();
 int totalPage = 0 ;
 if(rs.next())
 {
  totalPage = (rs.getInt(1) + perPage - 1)/perPage ;//求总页数
 }
 request.setAttribute("page",new Integer(page));  //放到request作用域中以便EL表达式使用!!
 request.setAttribute("totalPage", new Integer(totalPage));
 request.setAttribute("articles"articles);//放到request作用域中以便EL表达式使用!!
 request.getRequestDispatcher("/articleList.jsp").forward(request,response);//注意这里的绝对路径是绝对于上下文的!
 
}
catch(Exception ex)
{
 e.printStackTrace();
}
finally
{
 if(conn!=null)
 {
  conn.close();
  conn = null ;
 }
}

 

articleList.jsp:

<% taglib uri="/WEB-INF/c.tld" prefix="c"%>


<body>
 <table border=1>
  <c:forEach var="article" items="${requestScope.articles}">
   <tr>
    <td>${article.id}</td> //相当于调用map的get("id")
    <td><a href="content.jsp?id=${article.id}">${article.title}</a></td>
    <td>${article.time}</td>
   </tr>
  </c:forEach>

  <tr>//注意这里没有考虑首页和尾页的情况!!
   <td colspan=3 align=right>
   <c:if test="${requestScope.page<requestScope.totalPage}">
    <a href="list?page={requestScope.page+1}">下一页</a>
   </c:if test="${page>0}">
   <c:if test="${page>0}">
   <a href="list?page={requestScope.page-1}">上一页</a>   

   <c:if test="${page<=0}">
    上一页
   </c:if>
   </td>
  </tr>
 </table>
</body>


还有一点需要说明,如果用户直接访问jsp页面的话就不好了,第一次会什么都显示不出来,所以可以考虑将jsp页面放入到
WEB-INF目录下,这样客户端就无法访问了,请求转发可以转发到WEB-INF里面的页面,而且include指令也可以包含那些
WEB-INF里面的页面,include动作也是可以包含WEB-INF

上面的代码并不完整…………
===========================================================
附上老师的源代码如下所示:


package servlet;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class ListServlet extends HttpServlet {

 
 int perPage = 10;
 /**
  * The doGet method of the servlet. <br>
  *
  * This method is called when a form has its tag value method equals to get.
  *
  * @param request the request send by the client to the server
  * @param response the response send by the server to the client
  * @throws ServletException if an error occurred
  * @throws IOException if an error occurred
  */
 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {

  doPost(request, response);
 }

 /**
  * The doPost method of the servlet. <br>
  *
  * This method is called when a form has its tag value method equals to post.
  *
  * @param request the request send by the client to the server
  * @param response the response send by the server to the client
  * @throws ServletException if an error occurred
  * @throws IOException if an error occurred
  */
 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {

  Connection conn = null;
  PreparedStatement pstmt = null;
  ResultSet rs = null;
  int page = 0;
  
  
  try {
   page = Integer.parseInt(request.getParameter("page"));
   perPage = Integer.parseInt(request.getParameter("perPage"));
  } catch (NumberFormatException e1) {
   page = 0;
  }
  
  
  try {
   Context ctx = new InitialContext();
   DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/data");
   conn = ds.getConnection();
   pstmt = conn.prepareStatement("select * from articles limit ?, ?");
   pstmt.setInt(1, page*perPage);
   pstmt.setInt(2, perPage);
   
   
   
   rs = pstmt.executeQuery();
   
   ArrayList articles = new ArrayList();
   while(rs.next()) {
    Map map = new HashMap();
    map.put("id", new Integer(rs.getInt(1)));
    map.put("title", rs.getString(2));
    //map.put("content", rs.getString(3));
    map.put("time", rs.getTimestamp(4));
    articles.add(map);
   }
   
   pstmt = conn.prepareStatement("select count(*) from articles");
   rs = pstmt.executeQuery();
   int totalPage = 0;
   if(rs.next()) {
    totalPage = (rs.getInt(1)+perPage-1)/perPage;
   }
   
   request.setAttribute("page", new Integer(page));
   request.setAttribute("totalPage", new Integer(totalPage));
   request.setAttribute("articles", articles);
   
   request.getRequestDispatcher("/WEB-INF/hiddenJsp/articleList.jsp").forward(request, response);
   
   
   
  } catch (NamingException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (SQLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally {
   try {
    if(conn!=null) {
     conn.close();
     conn = null;
    }
   } catch (SQLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }

}

 

 


articleList.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  
    <title>My JSP 'articlList.jsp' starting page</title>
   
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
   
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>
 
  <body>
    <table border=1>
      <c:forEach var="article" items="${articles}">
        <tr>
          <td>${article.id}</td>
          <td><a href="content.jsp?id=${article.id}">${article.title}</a></td>
          <%--<td>${article.time}</td>--%>
        </tr>
      </c:forEach>
      <tr>
       <td colspan=2 align=right>
       <form action="list">
        <c:if test="${page>0}">
          <a href="list?page=${page-1}">上一页</a>
        </c:if>
        <c:if test="${page<=0}">
          上一页
        </c:if>
        <c:if test="${page<totalPage-1}">
          <a href="list?page=${page+1}">下一页</a>
        </c:if>
        <c:if test="${page>=totalPage-1}">
          下一页
        </c:if>
        每页显示<input type="text" name="perPage" size="1" maxLength="2" />
        <input type="hidden" name="page" value="0" />
       </form>
       </td>
      </tr>
    </table>
  </body>
</html>

 


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>
   
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
   
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>
 
  <body>
    <a href="${pageContext.request.contextPath}/list">查看留言</a>
  </body>
</html>
================================================================================
================================================================================
================================================================================
晚上模仿老师的例子又弄了一下那个分页,一到分页这里我就有些磕磕绊绊的,再加上核心标签库,弄的我状态非常的差…………

index页面和老师的一样,就一句代码:

<a href="${pageContext.request.contextPath}/PageDisplayServlet">查看所有的留言</a>

 

PageDisplayServlet:
读取数据库,取出第x页到第y页的记录并且存入ArrayList中

由于我使用的是DataSource数据源,所以需要配置server.xml:
 <Context path="/tag" docBase="tag"
  debug="5" reloadable="true" crossContext="true">


  <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
               maxActive="100" maxIdle="30" maxWait="10000"
               username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
               url="jdbc:mysql://localhost:3306/bbs?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=GBK"/>

 </Context>


package cn.itcast.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

public class PageDisplayServlet extends HttpServlet {
 
 int perPage = 3 ;    //每页的显示记录数
 int curPage = 1 ;    //当前的页数
 //之所以把这两个参数放到do方法外面是因为这两个方法可能会被留言板页面更改,比如我更改了每页显示的记录数,
 //但是我没有要显示下一页,这时候如果curPage=1是放到了do方法里面的话,则会被自动还原为1。而perPage如果
 //放到了do方法里面的话,每一次执行点击下一页或是上一页的时候,都会被还原为一次显示3条记录!

 public void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
  request.setCharacterEncoding("GBK");
  response.setContentType("text/html;charset=GBK");
  PrintWriter out = response.getWriter();
  
  String per = request.getParameter("per");//由留言板的表单提交而来
  String cur = request.getParameter("curPage");//由留言板的链接提交而来
  //由Jsp请求得到当前页数的参数!!!
  
  int totalCount = 0;  //总记录数
  int pageSize = 0 ;   //总页数
  
  if(cur!=null)
  {
   curPage = Integer.parseInt(cur);
   //如果请求不为空说明是从留言板页面跳转来的。
  }
  if(per != null)
  {
   perPage = Integer.parseInt(per) ;
   //如果请求不为空则说明是从留言板页面跳转而来,需要重新设定每页显示的记录数目!
  }
  
  Connection conn = null ;
  PreparedStatement pstmt = null ;
  ResultSet rs = null ;
  ArrayList list = new ArrayList();
  
  
  
  try
  {
   Context ctx = new InitialContext();//注意这三行的数据源连接法!!!
   DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/TestDB");
   conn = ds.getConnection();
   
   //分页代码,取出第x条到第y条的记录!
   pstmt = conn.prepareStatement("select * from message limit ?,?");
   pstmt.setInt(1,(curPage-1)*perPage);
   pstmt.setInt(2,perPage);
   rs = pstmt.executeQuery();
   while(rs.next())
   {
    Map map = new HashMap(); //和老师一样使用map而不是javaBean来存储每行记录,这样就省得写一个新的类了。
    map.put("messageid",new Integer(rs.getInt(1)));
    map.put("messagetitle",rs.getString(2));
    map.put("messagetime",rs.getString(4));
    list.add(map);
   }
   
   pstmt = conn.prepareStatement("select count(*) from message");
   rs = pstmt.executeQuery() ;
   if(rs.next())
   {
    totalCount = rs.getInt(1);//得到总记录数;
   }
   pageSize = (totalCount + perPage - 1)/perPage;//得到总页数
   
   //下面三句代码把集合、总页数、当前页数分别存入request作用域,是为了
   //能够让表达式语言直接使用!
   request.setAttribute("list",list);
   request.setAttribute("page",new Integer(curPage));
   request.setAttribute("pageSize",new Integer(pageSize));
  }
  catch (NamingException e)
  {   
   e.printStackTrace();
   System.out.println("数据源DataSource获取连接出现异常");
  }
  catch (SQLException e)
  {   
   e.printStackTrace();
   System.out.println("与数据库交互时出现问题");
  }
  finally
  {
   try {
    if(rs!=null)
    {
     rs.close();
     rs = null ;
    }
    if(pstmt!=null)
    {
     pstmt.close();
     pstmt = null ;
    }
    if(conn!=null&&!conn.isClosed())
    {
     conn.close();
     conn = null ;
    }
   } catch (SQLException e) {    
    e.printStackTrace();
    System.out.println("关闭资源出现了问题");
   }
  }
  //动态获得jsp路径
  String contextPath = request.getContextPath();
  //System.out.println(contextPath+"/messageList.jsp");  
  //request.getRequestDispatcher(contextPath+"/messageList.jsp").forward(request,response);
  //请求转发给jsp
  request.getRequestDispatcher("/messageList.jsp").forward(request,response);
  //这里请再次注意请求转发的绝对路径指的是什么!我已经不只一次在这里栽跟头了!!!
  
 }

 public void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {

  doGet(request,response);
 }

}


messageList.jsp:


<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/c.tld" prefix="c"%>
<%
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 'messageList.jsp' starting page</title>
   
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
   
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>
 
  <body>
    <h1 align=center>欢迎查看留言板</h1>
    <TABLE align="center" border="1" width="400" height="300">
     <tr>
      <th>帖子号</th>
      <th>帖子标题</th>
      <th>发贴时间</th>      
     </tr>
     <c:forEach var="message" items="${requestScope.list}">
     <tr>      //上面那个requestScope不加的话也可以,只要能够确认别的作用域里面没有同名属性就行!
      <td>${message.messageid}</td>
      <td>${message.messagetitle}</td>
      <td>${message.messagetime}</td>
     </tr>
     </c:forEach>
     <tr>
      <td colspan="3" align="center">
       <form action="PageDisplayServlet" method="post">
        请输入您想显示的每页显示的记录数:
        <input type=text name="per" size="3">&nbsp;&nbsp;
        <input type=submit value="确定">
       </form>
      </td>
     </tr>
    </TABLE>
    
    <c:choose>
     <c:when test="${page==1}">
      <p align="center">
       首页&nbsp;&nbsp;
       上一页&nbsp;&nbsp;
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page+1}">下一页</a>&nbsp;&nbsp;
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${pageSize}">尾页</a>&nbsp;&nbsp;
       当前是第${page}页&nbsp;&nbsp;
       一共${pageSize}页&nbsp;&nbsp;
      </p>
     </c:when>
     <c:when test="${page==pageSize}">
      <p align="center">
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=1">首页</a>&nbsp;&nbsp;
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page-1}">上一页</a>&nbsp;&nbsp;
       下一页&nbsp;&nbsp;
       尾页&nbsp;&nbsp;
       当前是第${page}页&nbsp;&nbsp;
       一共${pageSize}页&nbsp;&nbsp;
      </p>
     </c:when>
     <c:otherwise>
      <p align="center">
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=1">首页</a>&nbsp;&nbsp;
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page-1}">上一页</a>&nbsp;&nbsp;
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page+1}">下一页</a>&nbsp;&nbsp;
       <a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${pageSize}">尾页</a>&nbsp;&nbsp;
       当前是第${page}页&nbsp;&nbsp;
       一共${pageSize}页&nbsp;&nbsp;
      </p>
     </c:otherwise>
    </c:choose>
   
  </body>
</html>

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值