Servlet+JSP(二)

一、 JSP技术

JSP的英文全称为Java Server Page,翻译成中文就是Java服务器页面。JSP是Servlet的扩展技术。在JSP出现之前,只能够通过在Servlet中使用输出流动态输出HTML页面。但是,由于大量的HTML标签、文本、格式等等,导致了Servlet的开发效率非常低。JSP的出现弥补了Servlet的不足。JSP技术运行在页面上编写HTML代码,也允许编写Java代码。

1.1 第一个JSP程序

<%@ page language="java" import="java.util.*,java.text.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% 
	//获取系统的当前时间
	Date d = new Date();
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm::ss");
	String dateStr = sdf.format(d);
	out.write(dateStr);
%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<h1>这是我们第一个JSP程序</h1>
</body>
</html>

1.2 JSP的运行原理

浏览器第一次访问JSP页面的时候,Tomcat服务器会把该JSP文件翻译一个java类,该java类其实就是一个Servlet类。我们在页面上看到的内容,其实就是该Servlet的service方法输出的内容。
在这里插入图片描述

1.2 JSP的组成

1.2.1 JSP注释

JSP注释:<%-- JSP注释内容 --%>

HTML注释和JSP注释的区别?

HTML注释可以在浏览器上通过查看源码看到,而JSP注释不能够在浏览器中看到。所以,JSP注释的安全性更高。

1.2.2 脚本区

脚本区就是用来编写java代码的一个区域。

定义脚本区的格式:

<%
	java代码…
%>

一个JSP页面可以包含多个脚本区。而且后面定义的脚本区可以访问前面定义的脚本区中的内容。脚本区的java代码会在翻译后的Servlet类的service方法中直接运行。

1.2.3 脚本表达式

作用:代替out.write()语句的。

定义格式:

<%=输出的内容%>

注意:脚本表达式中的内容就是out.write()方法中内容。

案例:在JSP页面上把集合的内容遍历出来

第一步:新建一个Servlet。

public class ListBookServlet extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		//准备数据
		ArrayList<Book> books = new ArrayList<Book>();
		books.add(new Book("110", "西游记", 99));
		books.add(new Book("220", "红楼梦", 89));
		books.add(new Book("330", "葵花宝典", 199));
		books.add(new Book("440", "九阴真经", 100));
		//把集合放入到域对象中再发送给JSP
		req.setAttribute("books", books);
		//请求转发给listBook.jsp页面
		req.getRequestDispatcher("/listBook.jsp").forward(req, resp);
	}
	
}

第二步:新建JSP文件。

<%@ page language="java" import="java.util.List,day01.Book" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<table border=1 width=300 align=center cellspacing=0>
	<% 
		List<Book> books = (List<Book>) request.getAttribute("books");
		for (Book book : books) {
	%>
		<tr>
			<td><%=book.getId()%></td>
			<td><%=book.getTitle()%></td>
			<td><%=book.getPrice()%></td>
		</tr>
	<%
		}
	%>
	</table>
</body>
</html>

1.2.4 JSP处理指令

1.2.4.1 Page指令

作用:告诉浏览器如何来解析该JSP页面。

定义格式:

<%@page language=”java” import=”包1,包2,..” pageEncoding=”JSP页面的字符集”  errorPage=”” isErrorPage=””%>

errorPage:当前JSP页面出现异常,那么就会跳转该属性指定的页面;
isErrorPage:指定该JSP页面是一个异常的处理页面;

注意:每一个JSP页面都至少要包含一个page指令。而且page指令一般都是定义JSP页面的最上面。

1.2.4.2 Include指令

作用:包含其他的JSP页面。

定义格式:

<%@ include file=”JSP页面的路径”%>

注意: 使用include指令包含其他页面,那么被包含页面会与包含的JSP页面会被编译成一个Servlet类。因此,为了避免相同处理指令引起的冲突,被包含页面中不能够出现与包含页面中相同的处理指令。

1.2.4.3 taglib指令

作用:导入标签库文件。

定义格式:

<%@ taglib uri=”标签库URI” prefix=”标签别名”%>

1.3 jsp的九大内置对象

内置对象就是不需要我们创建的,可以在JSP直接使用的对象。

JSP的九大内置对象:

  • page:就是一个this对象,该this代表当前的JSP页面;
  • request:Servlet中的Request对象;
  • session:Servlet中的Session对象;
  • response:Servlet中的Response对象;
  • application:Servlet中的ServletContext对象;
  • config:Servlet中的ServletConfig对象;
  • pageContext:Servlet中的PageContext对象;
  • out:带缓存的PrintWriter对象
  • exception:异常对象。该内置对象只有当出现了异常的时候,如果JSP页面被设置为错误处理页面,那么Tomcat服务器就会把异常对象exception传入该JSP里面;
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% 
	//获取内置对象获取Servlet域对象的数据
	//Object o = request.getAttribute("name");
	Object o = session.getAttribute("name");
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%-- 获取到的request属性:<%=o%><br/> --%>
	获取到Session属性:<%=o%>
</body>
</html>

二、 EL表达式

EL的英文全称为:Expression Language,中文意思是表达式语言。EL表达式的出现让JSP的代码更加的简单。
例如:它可以替代脚本表达式。

2.1 EL的使用

EL表达式的格式:

${内置对象名.属性名}

2.2 EL的内置对象

EL表达式的内置对象与JSP的四大域对象相对应。

EL内置对象Servlet内置对象
pageScopepageContext
requestScoperequest
sessionScopesession
applicationScopeapplication

一般情况下,对象名可以不写。如果不写对象名,那么JSP就会从PageScope > requestScope > sessionScope > applicationScope这些域对象查找是否存在指定的属性。如果存在,那么就不会继续往后查找。

2.2 EL运算符

算术运算符:+ - * / %

比较运算符:> >= < <= !=

逻辑运算符:or(逻辑或) and(逻辑与) not(逻辑非)

empty运算符:如果判断的是字符串,那么如果字符串为空,那么就返回true。否则返回false。如果判断的是集合,那么如果集合没有元素,那么就返回true,否则返回false;

三目运算符:条件表达式 ? ‘内容1’ : ‘内容2’;

三、 JSTL标签

3.1 JSTL标签库介绍

从JSP 1.1规范开始,JSP就支持使用自定义标签,使用自定义标签大大降低了JSP页面的复杂度,同时增强了代码的重用性,因此自定义标签在WEB应用中被广泛使用。许多WEB应用厂商都开发出了自己的一套标签库提供给用户使用,这导致出现了许多功能相同的标签,令网页制作者无所适从,不知道选择哪一家的好。为了解决这个问题,Apache Jakarta小组归纳汇总了那些网页设计人员经常遇到的问题,开发了一套用于解决这些常用问题的自定义标签库,这套标签库被SUN公司定义为标准标签库(The JavaServer Pages Standard Tag Library),简称JSTL。使用JSTL可以解决用户选用不同WEB厂商的自定义标签时的困惑,JSP规范同时也允许WEB容器厂商按JSTL标签库的标准提供自己的实现,以获取最佳性能。由于JSTL是在JSP 1.2规范中定义的,所以JSTL需要运行在支持JSP 1.2及其更高版本的WEB容器上,例如,Tomcat 5.5。

JSP的最佳实践:
JSP只负责页面数据的展示,而Servlet负责了具体的业务处理。因此,在实际开发中,JSP尽量不要写任何的Java代码。如果要在JSP页面中不写任何java代码,那么就需要学习EL表达式和JSTL标签。

3.2 使用JSTL标签的步骤

第一步:把jstl的jar包拷贝到工程中
在这里插入图片描述
第二步:在JSP页面中导入标签库文件

<%taglib uri=”http://java.sun.com/jsp/jstl/core” prefix=”c”%>

其中,uri代表标签库的URI地址,prefix代表标签库的别名。
在这里插入图片描述

  • 核心标签库:包含了实现WEB应用中的通用操作的标签。例如,用于输出一个变量内容的<c:out>标签、用于条件判断的<c:if>标签、用于迭代循环的<c:forEach>标签。

  • 国际化/格式化标签库:包含实现WEB应用程序的国际化的标签。例如,设置JSP页面的本地信息、设置JSP页面的时区、绑定资源文件,使本地敏感的数据(例如数值、日期等)按照JSP页面中设置的本地格式显示。

  • 数据库标签库:包含用于访问数据库和对数据库中的数据进行操作的标签。例如,从数据源中获得数据库连接、从数据库表中检索数据等。由于在软件分层的开发模型中,JSP页面仅用作表现层,我们一般不在JSP页面中直接操作数据库,而是在业务逻辑层或数据访问层操作数据库,所以,JSTL中提供的这套数据库标签库没有多大的实用价值。

  • XML标签库:包含对XML文档中的数据进行操作的标签。例如,解析XML文档、输出XML文档中的内容,以及迭代处理XML文档中的元素。因为XML广泛应用于WEB开发,对XML文档的处理非常重要,XML标签库使处理XML文档变得简单方便,这也是JSTL的一个重要特征。

  • 函数标签:JSTL中提供的一套EL自定义函数包含了JSP页面制作者经常要用到的字符串操作。例如,提取字符串中的子字符串、获取字符串的长度和处理字符串中的空格等。

第三步:使用该标签库中的标签。

3.3 常用标签

3.3.1 核心标签库

3.3.1.1 条件标签

定义格式:

<c:if test=”el条件表达式”>
	…
</c:if>

注意:if标签没有else。

3.3.1.2 循环标签

语法格式:

<c:foreach items=”el表达式” var=”域对象属性名”>
	${属性名}
</c:foreach>

注意:items的值必须是一个数组或集合的数据。

foreach标签遍历数组或集合元素的时候,它会把遍历出来的元素保存到一个域对象的属性中,该属性的名字就是var的值。

3.3.2 格式化标签

3.3.2.1 日期格式化标签

语法格式:

<fmt:formatDate value=”${日期}” pattern=”日期模式”/>

例如:2018年2月7日 11:05:10,对应的模式为yyyy年MM月dd日 HH:mm:ss。

3.3.3 函数标签

使用语法:

${fn:函数名(对象名.属性名)}

常用的函数标签:

  • toLowerCase():把字符串全部转换小写;
  • toUpperCase():把字符串全部转换大写;
  • ength():获取字符串的长度;
  • substring():截取字符串;

四、 自定义标签

4.1 自定义标签的步骤

需求:定义一个标签,向页面输出当前的系统时间。

第一步:定义一个标签处理类,该类继承SimpleTagSupport父类,并重写doTag方法;

/*
	显示系统当前时间的标签处理类
*/
public class ShowTimeTag extends SimpleTagSupport {

	//该方法实现自定义标签的业务功能
	@Override
	public void doTag() throws JspException, IOException {
		//获取系统的当前时间
		Date d = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
		String dateStr = sdf.format(d);
		//把时间输出到页面上
		this.getJspContext().getOut().write("系统当前的时间:" + dateStr);
	}

}

第二步:在WEB-INF目录下新建一个tld文件,文件的名字可以是任意名字。该文件是自定义标签的配置文件;

第三步:在tld文件中配置标签;

<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
	version="2.0">

	<!-- 标签库文件的描述信息 -->	
	<description>JSTL 1.1 core library</description>
	<!-- 标签库文件的名字 -->
	<display-name>JSTL core</display-name>
	<!-- 标签库的版本 -->
	<tlib-version>1.1</tlib-version>
	<!-- 标签库的推荐使用的别名 -->
	<short-name>mytags</short-name>
	<!-- 标签库的URI地址 ,一般使用公司域名的格式 -->
	<uri>/mytags</uri>

	<!-- 定义标签,一个tag定义一个标签 -->
	<tag>
		<!-- 标签名 -->
		<name>systime</name>
		<!-- 标签处理类 -->
		<tag-class>day01.ShowTimeTag</tag-class>
		<!-- 标签体的内容 -->
		<body-content>scriptless</body-content>
	</tag>

</taglib>

第四步:在JSP页面上导入自定义标签库;

<!-- 导入自定义标签库 -->
<%@ taglib uri="/mytags" prefix="mytags" %>

第五步:使用自定义标签;

<!-- 获取系统的当前时间 -->
<mytags:systime/>	

4.2 自定义标签的执行过程

当Tomcat服务器启动的时候,它会自动加载WEB-INF目录下的所有tld文件。如果浏览器访问JSP页面的时候,那么Tomcat服务器会解析自定义标签的URI地址。然后它会从所有tld文件中查找是否存在该URI地址的tld文件。如果找到后,那么就会继续在该tld文件中查找是否存在一个name属性为systime的tag标签。如果找到后,那么Tomcat就会把tag-class子节点解析出来,然后通过反射技术创建Class对象,并调用该对象的doTag方法来实现自定义标签的业务处理。

4.3 自定义标签的生命周期

在这里插入图片描述

  • setJspBody():如果有标签体,该方法会把标签体内容传入到标签处理类中;
  • setJspContext():通过该方法,服务器把PageContext对象传入到标签处理类中;
  • setParent():如果有父标签,该方法把父标签传入到标签处理类中;
  • doTag():负责标签的业务处理(需要自己实现);
  • getJspBody():获取标签体内容,该方法返回一个JspFrament对象,该对象封装了标签体的内容;
  • getJspContext():获取PageContext对象。该对象的作用:1)获取其他域对象;2)获取输出流,向页面输出内容;
  • getParent():获取当前标签的父标签,该方法返回一个JspTag对象,该对象代表父标签;

执行doTag方法之前,Tomcat服务器会先自动执行一些setXxx方法。这些setXxx方法是Tomcat服务器自动调用,不需要我们操作。执行完成后,在doTag方法中就可以调用这些setXxx方法对应的getter方法,获取对应的内容。

4.4 自定义标签的常见操作

4.4.1 控制标签体内容是否显示

输出:this.getJspBody().invoke(null);
不输出:什么都不做!

public class HelloTag extends SimpleTagSupport {

	//实现标签的业务功能
	@Override
	public void doTag() throws JspException, IOException {
		System.out.println("doTag...");
		//输出标签体的内容
		/*JspWriter writer = this.getJspContext().getOut(); //向网页输出内容的输出流
		this.getJspBody().invoke(writer);*/
		this.getJspBody().invoke(null); //如果invoke方法的参数为null,那么默认就是把标签体内容输出到网页
	}
	
}

4.4.2 控制标签外面的内容是否显示

输出:什么都不做!
不输出:抛出SkipPageException异常!

4.4.3 重复输出标签体的内容

如果自定义标签中包含属性,那么需要在tld文件中配置属性。

<tag>
		<!-- 标签名 -->
		<name>test</name>
		<!-- 标签处理类 -->
		<tag-class>day01.tags.TestTag</tag-class>
		<!-- 标签体的内容 -->
		<body-content>scriptless</body-content>
		<!-- 配置标签属性 -->
		<attribute>
			<!-- 属性名 -->
			<name>count</name>
			<!-- 是否必须的 -->
			<required>true</required>
			<!-- 是否支持表达式 -->
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

然后,在标签处理类中需要指定一个成员属性,该成员属性的名字与标签属性名相同。而且还需要为该属性提供setter方法。

public class TestTag extends SimpleTagSupport {
	private int count;
	
	public void setCount(int count) {
		this.count = count;
	}

	//该方法实现自定义标签的业务功能
	@Override
	public void doTag() throws JspException, IOException {
		//显示标签体的内容
		//this.getJspBody().invoke(null);
		
		//不显示标签外面的内容
		//throw new SkipPageException();
		
		//循环输出标签体内容
		while (count > 0) {
			this.getJspBody().invoke(null);
			count--;
		}
	}

}

4.4.4 改变标签体内容

public class UpperCaseTag extends SimpleTagSupport {

	//该方法实现自定义标签的业务功能
	@Override
	public void doTag() throws JspException, IOException {
		//获取标签体的内容
		JspFragment jspBody = this.getJspBody();
		//创建StringWriter对象
		StringWriter out = new StringWriter();
		//把标签体写入到输出流中
		jspBody.invoke(out);
		//获取输出流中的内容
		String content = out.toString().toUpperCase();
		//输出页面上
		this.getJspContext().getOut().write(content);
	}

}

4.5 自定义标签案例

4.5.1 实现if标签

<mytags:if test="${gender == 1}"></mytags:if>
<mytags:if test="${gender != 1}"></mytags:if>

在tld文件中配置标签:

<tag>
	<!-- 标签名 -->
	<name>if</name>
	<!-- 标签处理类 -->
	<tag-class>day01.tags.IfTag</tag-class>
	<!-- 标签体的内容 -->
	<body-content>scriptless</body-content>
	<attribute>
		<name>test</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
</tag>

实现标签处理类:

/*
 * if标签
 */
public class IfTag extends SimpleTagSupport {
	private boolean test;
	
	public void setTest(boolean test) {
		this.test = test;
	}

	//该方法实现自定义标签的业务功能
	@Override
	public void doTag() throws JspException, IOException {
		if (test) {
			//输出标签体内容
			this.getJspBody().invoke(null);
		}
	}

}

4.5.2 实现foreach标签

<!-- 遍历collection -->
	<mytags:foreach items="${books}" var="book">
		${book}<br/>
	</mytags:foreach>
	
	<!-- 遍历Map -->
	<mytags:foreach items="${couples}" var="couple">
		${couple.key} --> ${couple.value}
	</mytags:foreach>
	
	<!-- 遍历数组 -->
	<mytags:foreach items="${persons}" var="person">
		${person}<br/>
	</mytags:foreach>

在tld文件中配置标签:

<tag>
	<!-- 标签名 -->
	<name>foreach</name>
	<!-- 标签处理类 -->
	<tag-class>day01.ForeachTag</tag-class>
	<!-- 标签体的内容 -->
	<body-content>scriptless</body-content>
	<attribute>
		<name>items</name>
		<required>true</required>
		<rtexprvalue>true</rtexprvalue>
	</attribute>
	<attribute>
		<name>var</name>
		<required>true</required>
		<rtexprvalue>false</rtexprvalue>
	</attribute>
</tag>

实现标签处理类:

/*
 * foreach标签
 */
public class ForeachTag extends SimpleTagSupport {
	private Object items;
	private String var;
	
	public void setItems(Object items) {
		this.items = items;
	}

	public void setVar(String var) {
		this.var = var;
	}

	//该方法实现自定义标签的业务功能
	@Override
	public void doTag() throws JspException, IOException {
		//如果items是Collection集合
		if (items instanceof Collection) {
			Collection c = (Collection) items;
			//遍历Collection集合
			Iterator itr = c.iterator();
			while (itr.hasNext()) {
				Object element = itr.next();
				//把元素添加到域对象中
				this.getJspContext().setAttribute(var, element);
				//输出标签体内容
				this.getJspBody().invoke(null);
			}
		} else if (items instanceof Map) {
			Map map = (Map) items;
			//遍历Map
			Set<Map.Entry<String, String>> entrySet = map.entrySet();
			for (Map.Entry<String, String> entry : entrySet) {
				//把每一个entry都添加到域对象中
				this.getJspContext().setAttribute(var, entry);
				//输出标签体内容
				this.getJspBody().invoke(null);
			}
		} else if (items.getClass().isArray()) {
			//获取数组长度
			int len = Array.getLength(items);
			//遍历数组
			for (int i = 0; i < len; i++) {
				//根据下标获取数组元素
				Object element = Array.get(items, i);
				//把元素添加到域对象中
				this.getJspContext().setAttribute(var, element);
				//输出标签体内容
				this.getJspBody().invoke(null);
			}
			
		}
	}

}

五、分页实现

当数据量非常大的时候,如果把所有数据都显示在一个页面上,对用户的体验来说非常不好。所以,一般会进行分页显示数据。

5.1 分页基本实现

第一步:拷贝相关jar包;
在这里插入图片描述

第二步:创建一个实体类。

/*
 * 学员实体类
 */
public class Student {
	private int id;
	private String name;
	private int age;
	private int score;
	
	//提供无参构造函数
	public Student() {
		
	}
	
	public Student(int id, String name, int age, int score) {
		this.id = id;
		this.name = name;
		this.age = age;
		this.score = score;
	}

	// 省略了setters和getters方法...
	
}

第三步:编写Dao类,实现分页查询功能。

/*
 * 提供一些基本的数据库操作
 */
public class BaseDao {
	//连接池对象
	private static ComboPooledDataSource ds = new ComboPooledDataSource();
	//不带事务QueryRunner对象
	private static QueryRunner queryRunner = new QueryRunner(ds);

	/**
	 * 实现数据库的增删改操作
	 * @throws SQLException 
	 */
	public void update(String sql, Object[] params) throws SQLException {
		queryRunner.update(sql, params);
	}
	
	/**
	 * 该方法主要把查询的结果封装成JavaBean对象或者List集合,并返回该对象。
	 * @param sql 要执行的SQL
	 * @param params 传入的参数
	 * @param rh 专门处理结果的处理器。
	 * @return 如果传入的处理器是BeanHandler对象,那么返回一个JavaBean对象。如果传入的是BeanListHandler,那么返回一个List集合
	 * @throws Exception 
	 */
	public Object find(String sql, Object[] params
			, ResultSetHandler rsh) throws Exception {
		return queryRunner.query(sql, rsh, params);
	}
	
}

第四步:编写Servlet类。

/**
 * 分页显示学员列表
 */
@WebServlet("/student/list.do")
public class ListStudentServlet extends HttpServlet {
	private StudentDao studentDao = new StudentDao();
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//获取请求参数
		int currPage = request.getParameter("currPage") == null ? 1
				: Integer.parseInt(request.getParameter("currPage"));
		int pageSize = request.getParameter("pageSize") == null ? 5
				: Integer.parseInt(request.getParameter("pageSize"));
		//计算开始查询的行号:(currPage - 1) * pageSize
		int startRow = (currPage - 1) * pageSize;
		//执行查询
		try {
			List<Student> students = studentDao.findAll(startRow, pageSize);
			//把数据添加到域对象
			request.setAttribute("students", students);
			//总的记录数 
			int total = studentDao.getTotal();
			request.setAttribute("total", total);
			/*
			 * 计算总的页数:
			 * 	1) 如果总记录数可以被pageSize整数:总页数 = 总记录数 / 每页显示的记录数
			 *  2) 如果总记录数不能够被pageSize整数:总页数 = 总记录数 / 每页显示记录数 + 1
			 */
			int totalPage = 0; //总的页数
			if (total % pageSize == 0) {
				totalPage = total / pageSize;
			} else {
				totalPage = total / pageSize + 1;
			}
			request.setAttribute("totalPage", totalPage);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//把当前页数发送给JSP
		request.setAttribute("currPage", currPage);
		//请求转发到list.jsp页面
		request.getRequestDispatcher("/list.jsp").forward(request, response);
	}

	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		doGet(request, response);
	}

}

第五步:新建一个JSP页面,然后显示分页数据和分页信息。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!-- 导入jstl标签库 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<table border="1" cellspacing="0" width="500">
		<caption><h2>学生列表</h2></caption>
		<tr>
			<th>编号</th>
			<th>姓名</th>
			<th>年龄</th>
			<th>分数</th>
		</tr>
		<c:forEach items="${students}" var="student">
			<tr>
				<td>${student.id}</td>
				<td>${student.name}</td>
				<td>${student.age}</td>
				<td>${student.score}</td>
			</tr>
		</c:forEach>
		<tr>
			<td colspan="4" align="center">
				<a href="${pageContext.request.contextPath}/student/list.do?currPage=1">首页</a>
				<c:if test="${currPage == 1}">
					上一页
				</c:if>
				<c:if test="${currPage != 1}">
					<a href="${pageContext.request.contextPath}/student/list.do?currPage=${currPage-1}">上一页</a>
				</c:if>
				<a href="${pageContext.request.contextPath}/student/list.do?currPage=${currPage+1}">下一页</a>
				<a href="${pageContext.request.contextPath}/student/list.do?currPage=${totalPage}">尾页</a>
				当前第${currPage}页, 共${totalPage}页, 总记录数${total}
			</td>
		</tr>
	</table>
</body>
</html>

分页信息:1)当前的页数;2)总的记录数;3)总页数;

5.2 分页优化

java是面向对象的语言,一般在Java中的数据不会零散摆放。我们会把一些业务相关的数据保存到一个对象中。

新建一个PageModel来保存所有的分页数据和分页信息。

/*
 * 保存一些分页的信息和分页的数据
 */
public class PageModel<T> {
	private List<T> data; //分页数据
	//-----分页信息------
	private int currPage; //当前第几页
	private int total; //总的记录数
	private int totalPage; //总的页数
	private int pageSize;  //每页显示记录数
	
	// 省略了setters和getters方法...
	
}

然后,在Servlet中把所有的分页数据和分页信息保存到PageModel对象中,然后再发送给JSP页面。

@WebServlet("/student/list.do")
public class ListStudentServlet extends HttpServlet {
	private StudentDao studentDao = new StudentDao();
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//获取请求参数
		int currPage = request.getParameter("currPage") == null ? 1
				: Integer.parseInt(request.getParameter("currPage"));
		int pageSize = request.getParameter("pageSize") == null ? 5
				: Integer.parseInt(request.getParameter("pageSize"));
		
		PageModel<Student> pageModel = new PageModel<Student>();
		pageModel.setCurrPage(currPage);
		pageModel.setPageSize(pageSize);
		
		//计算开始查询的行号:(currPage - 1) * pageSize
		int startRow = (currPage - 1) * pageSize;
		//执行查询
		try {
			List<Student> students = studentDao.findAll(startRow, pageSize);
			pageModel.setData(students);
			//总的记录数 
			int total = studentDao.getTotal();
			pageModel.setTotal(total);
			/*
			 * 计算总的页数:
			 * 	1) 如果总记录数可以被pageSize整数:总页数 = 总记录数 / 每页显示的记录数
			 *  2) 如果总记录数不能够被pageSize整数:总页数 = 总记录数 / 每页显示记录数 + 1
			 */
			int totalPage = 0; //总的页数
			if (total % pageSize == 0) {
				totalPage = total / pageSize;
			} else {
				totalPage = total / pageSize + 1;
			}
			pageModel.setTotalPage(totalPage);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//把pageModel对象发送给JSP
		request.setAttribute("pageModel", pageModel);
		//请求转发到list.jsp页面
		request.getRequestDispatcher("/list.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		doGet(request, response);
	}
}

最后,修改JSP页面,通过EL表达式从pageModel中获取分页数据和分页信息。

<table border="1" cellspacing="0" width="500">
		<caption><h2>学生列表</h2></caption>
		<tr>
			<th>编号</th>
			<th>姓名</th>
			<th>年龄</th>
			<th>分数</th>
		</tr>
		<c:forEach items="${pageModel.data}" var="student">
			<tr>
				<td>${student.id}</td>
				<td>${student.name}</td>
				<td>${student.age}</td>
				<td>${student.score}</td>
			</tr>
		</c:forEach>
		<tr>
			<td colspan="4" align="center">
				<a href="${pageContext.request.contextPath}/student/list.do?currPage=1">首页</a>
				<c:if test="${pageModel.currPage == 1}">
					上一页
				</c:if>
				<c:if test="${pageModel.currPage != 1}">
					<a href="${pageContext.request.contextPath}/student/list.do?currPage=${pageModel.currPage-1}">上一页</a>
				</c:if>
				<a href="${pageContext.request.contextPath}/student/list.do?currPage=${pageModel.currPage+1}">下一页</a>
				<a href="${pageContext.request.contextPath}/student/list.do?currPage=${pageModel.totalPage}">尾页</a>
				当前第${pageModel.currPage}页, 共${pageModel.totalPage}页, 总记录数${pageModel.total}
			</td>
		</tr>
	</table>

5.3 自定义分页标签

自定义分页标签的格式:

<!-- 自定义分页标签 -->
<mytags:pager url="" currPage="" pageSize="" total="" totalPage=""/>

第一步:配置分页标签。

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
	version="2.0">

	<!-- 标签库文件的描述信息 -->	
	<description>JSTL 1.1 core library</description>
	<!-- 标签库文件的名字 -->
	<display-name>JSTL core</display-name>
	<!-- 标签库的版本 -->
	<tlib-version>1.1</tlib-version>
	<!-- 标签库的推荐使用的别名 -->
	<short-name>mytags</short-name>
	<!-- 标签库的URI地址 ,一般使用公司域名的格式 -->
	<uri>/mytags</uri>

	<!-- 定义标签,一个tag定义一个标签 -->
	<tag>
		<!-- 标签名 -->
		<name>pager</name>
		<!-- 标签处理类 -->
		<tag-class>day01.tags.PagerTag</tag-class>
		<!-- 标签体的内容 -->
		<body-content>scriptless</body-content>
		<!-- 定义属性 -->
		<attribute>
			<name>url</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>currPage</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>pageSize</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>total</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<name>totalPage</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

</taglib>

第二步:定义标签处理类。

/*
 * 分页标签处理类
 */
public class PagerTag extends SimpleTagSupport {
	private String url;
	private int currPage;
	private int total;
	private int pageSize;
	private int totalPage;
	
	public void setUrl(String url) {
		this.url = url;
	}

	public void setCurrPage(int currPage) {
		this.currPage = currPage;
	}

	public void setTotal(int total) {
		this.total = total;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}

	@Override
	public void doTag() throws JspException, IOException {
		StringBuilder sb = new StringBuilder();
		sb.append("<a href='" + url + "?currPage=1'>首页</a>&nbsp;");
		if (currPage == 1) {
			sb.append("上一页");
		} else {
			sb.append("<a href='" + url + "?currPage=" + (currPage - 1) + "'>上一页</a>&nbsp;");
		}
		if (currPage == totalPage) {
			sb.append("下一页");
		} else {
			sb.append("<a href='" + url + "?currPage=" + (currPage + 1) + "'>下一页</a>&nbsp;");
		}
		sb.append("<a href='" + url + "?currPage=" + totalPage + "'>尾页</a>&nbsp;");
		sb.append("当前第" + currPage + "页, 共" + totalPage + "页, 总记录数" + total);
		//把内容输出到JSP页面
		this.getJspContext().getOut().write(sb.toString());
	}
	
}

第三步:在JSP页面中导入自定义标签库;

<!-- 导入自定义标签库 -->
<%@ taglib uri="/mytags" prefix="mytags" %>

第四步:使用分页标签;

<!-- 自定义分页标签 -->
<mytags:pager 
	url="${pageContext.request.contextPath}/student/list.do" 
	currPage="${pageModel.currPage}" 
	pageSize="${pageModel.pageSize}" 
	total="${pageModel.total}" 
	totalPage="${pageModel.totalPage}"/>

  • 0
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论

打赏作者

老钟私房菜

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值