总结的一、二、三在培训日记的第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&useUnicode=true&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">
<input type=submit value="确定">
</form>
</td>
</tr>
</TABLE>
<c:choose>
<c:when test="${page==1}">
<p align="center">
首页
上一页
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page+1}">下一页</a>
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${pageSize}">尾页</a>
当前是第${page}页
一共${pageSize}页
</p>
</c:when>
<c:when test="${page==pageSize}">
<p align="center">
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=1">首页</a>
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page-1}">上一页</a>
下一页
尾页
当前是第${page}页
一共${pageSize}页
</p>
</c:when>
<c:otherwise>
<p align="center">
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=1">首页</a>
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page-1}">上一页</a>
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${page+1}">下一页</a>
<a href="${pageContext.request.contextPath}/PageDisplayServlet?curPage=${pageSize}">尾页</a>
当前是第${page}页
一共${pageSize}页
</p>
</c:otherwise>
</c:choose>
</body>
</html>