前言:在上一讲博客《Java Web基础入门第四十九讲 客户关系管理系统之分页查询》中,我们就完成了客户信息的分页查询,现在我们趁热打铁来实现学生信息的分页查询,做这个练习来巩固我们的知识。

创建MVC架构的Web项目

在Eclipse中新创建一个day15_page项目,导入项目所需要的开发包(jar包),创建项目所需要的包,在Java开发中,架构的层次是以包的形式体现出来的。

Java实现查询工商信息存储到数据库中 javaweb实现查询功能_java


Java实现查询工商信息存储到数据库中 javaweb实现查询功能_java_02


以上就是根据此项目的实际情况创建的包,可能还需要创建其他的包,这个得根据项目的需要来定了。

接着,为应用创建相应库和表。根据如下建表SQL语句在数据库中创建一张student表:

create database day15;
use day15;
create table student 
(
    id varchar(40),
    name varchar(40)
);

并使用如下SQL语句向student表中插入一些数据:

insert into student(id,name) values('1','aa1');
insert into student(id,name) values('2','aa2');
insert into student(id,name) values('3','aa3');
insert into student(id,name) values('4','aa4');
insert into student(id,name) values('5','aa5');
insert into student(id,name) values('6','aa6');
insert into student(id,name) values('7','aa7');
insert into student(id,name) values('8','aa8');
insert into student(id,name) values('9','aa9');
insert into student(id,name) values('10','aa10');
insert into student(id,name) values('11','aa11');
insert into student(id,name) values('12','aa12');
insert into student(id,name) values('13','aa13');
insert into student(id,name) values('14','aa14');
insert into student(id,name) values('15','aa15');
insert into student(id,name) values('16','aa16');
insert into student(id,name) values('17','aa17');
insert into student(id,name) values('18','aa18');
insert into student(id,name) values('19','aa19');
insert into student(id,name) values('20','aa20');
insert into student(id,name) values('21','aa21');
insert into student(id,name) values('22','aa22');
insert into student(id,name) values('23','aa23');

除此之外,还应在src目录下创建一个db.properties文件,在db.properties中编写MySQL数据库的连接信息,内容如下所示:

Java实现查询工商信息存储到数据库中 javaweb实现查询功能_java_03


最后,创建好的项目架构如下图所示:

Java实现查询工商信息存储到数据库中 javaweb实现查询功能_Java-Web基础_04

分层架构的代码编写

分层架构的代码也是按照【域模型层(domain)】→【数据访问层(dao、dao.impl)】→【业务逻辑层(service、service.impl)】→【表现层(web.controller、web.UI、web.filter、web.listener)】→【工具类(util)】→【测试类(junit.test)】的顺序进行编写的。

开发domain层

在cn.liayun.domain包下创建一个Student类,该类的具体代码如下:

package cn.liayun.domain;

public class Student {
	private String id;
	private String name;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

紧接着,创建实现分页显示的三个对象。在cn.liayun.domain包下创建QueryInfo类,用于封装用户的请求参数。

package cn.liayun.domain;

/**
 * 封装查询信息的实体
 * @author liayun
 *
 */
public class QueryInfo {
	private int currentpage = 1;//用户当前看的页
	private int pagesize = 5;//记住用户想看的页面大小
	private int startindex;//记住用户看的页的数据在数据库的起始位置
	
	public int getCurrentpage() {
		return currentpage;
	}
	public void setCurrentpage(int currentpage) {
		this.currentpage = currentpage;
	}
	public int getPagesize() {
		return pagesize;
	}
	public void setPagesize(int pagesize) {
		this.pagesize = pagesize;
	}
	public int getStartindex() {
		this.startindex = (this.currentpage - 1) * this.pagesize;
		return startindex;
	}
}

然后在cn.liayun.domain包下创建QueryResult类,用于封装查询结果。

package cn.liayun.domain;

import java.util.List;

/**
 * 用来封装查询结果的实体
 * @author liayun
 *
 */
public class QueryResult {
	private List list;//记住用户看的页的数据
	private int totalrecord;//记住总记录数
	
	public List getList() {
		return list;
	}
	public void setList(List list) {
		this.list = list;
	}
	public int getTotalrecord() {
		return totalrecord;
	}
	public void setTotalrecord(int totalrecord) {
		this.totalrecord = totalrecord;
	}
}

最后在cn.liayun.domain包下创建PageBean类,该类用于将QueryResult对象中封装的查询结果,生成显示分页数据的PageBean对象。

package cn.liayun.domain;

import java.util.List;

/**
 * 封装页面显示需要的信息
 * @author liayun
 *
 */
public class PageBean {
	private List list;
	private int totalrecord;
	private int pagesize;
	private int totalpage;
	private int currentpage;
	private int previouspage;
	private int nextpage;
	private int[] pagebar;
	
	public List getList() {
		return list;
	}
	public void setList(List list) {
		this.list = list;
	}
	public int getTotalrecord() {
		return totalrecord;
	}
	public void setTotalrecord(int totalrecord) {
		this.totalrecord = totalrecord;
	}
	public int getPagesize() {
		return pagesize;
	}
	public void setPagesize(int pagesize) {
		this.pagesize = pagesize;
	}
	public int getTotalpage() {
		//根据总记录数和页面大小算出来的
		//100	5	20
		//101	5	21
		//99	5	20
		if (this.totalrecord % this.pagesize == 0) {
			this.totalpage = this.totalrecord / this.pagesize;
		} else {
			this.totalpage = this.totalrecord / this.pagesize + 1;
		}
		return totalpage;
	}
	
	public int getCurrentpage() {
		return currentpage;
	}
	public void setCurrentpage(int currentpage) {
		this.currentpage = currentpage;
	}
	public int getPreviouspage() {
		if (this.currentpage - 1 < 1) {
			this.previouspage = 1;
		} else {
			this.previouspage = this.currentpage - 1;
		}
		
		return previouspage;
	}
	public int getNextpage() {
		if (this.currentpage + 1 >= this.totalpage) {
			this.nextpage = this.totalpage;
		} else {
			this.nextpage = this.currentpage + 1;
		}
		return nextpage;
	}
	public int[] getPagebar() {
		int startpage;
		int endpage;
		int[] pagebar = null;
		if (this.totalpage <= 10) {
			pagebar = new int[this.totalpage];
			startpage = 1;
			endpage = this.totalpage;
		} else {
			pagebar = new int[10];
			startpage = this.currentpage - 4;
			endpage = this.currentpage + 5;
			//总页数=30		3		-1
			//总页数=30		29		34
			if (startpage < 1) {
				startpage = 1;
				endpage = 10;
			}
			
			if (endpage > this.totalpage) {
				endpage = this.totalpage;
				startpage = this.totalpage - 9;
			}
		}
		
		int index = 0;
		for (int i = startpage; i <= endpage; i++) {
			pagebar[index++] = i;
		}
		this.pagebar = pagebar;
		return this.pagebar;
		/*
		int[] pagebar = new int[this.totalpage];
		for (int i = 1; i <= this.totalpage; i++) {
			pagebar[i - 1] = i;
		}
		this.pagebar = pagebar;
		return pagebar;
		*/
	}
}

开发数据访问层(dao、dao.impl)

在开发数据访问层时,由于要编写得到MySQL数据库链接和释放资源这些性质的操作,所以应该把它们放在一个工具类JdbcUtils中。于是,在cn.liayun.utils包下创建一个JdbcUtils类,类的具体代码如下:

package cn.liayun.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JdbcUtils {
	
	private static Properties config = new Properties();
	
	// 静态代码块只执行一次,因为静态代码块在类加载时执行,类永远只加载一次
	static {
		try {
			config.load(JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"));
			Class.forName(config.getProperty("driver"));
		} catch (Exception e) {
			/*
             * db.properties文件都无法读取,那么整个应用程序就无法连接数据库,
             * 驱动都加载不了,那么整个应用程序都无法工作,
             * 所以应该抛一个错误(ExceptionInInitializerError)
             */
			throw new ExceptionInInitializerError(e);
		}
	}

	public static Connection getConnection() throws SQLException {
		return DriverManager.getConnection(config.getProperty("url"), config.getProperty("username"), config.getProperty("password"));
	}
	
	public static void release(Connection conn, Statement st, ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			rs = null;
		}
		
		if (st != null) {
			try {
				st.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			st = null;
		}
		
		if (conn != null) {
			try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
	
}

最后,在cn.liayun.dao包下创建一个StudentDao类,该类的具体代码如下:

package cn.liayun.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import cn.liayun.domain.QueryResult;
import cn.liayun.domain.Student;
import cn.liayun.utils.JdbcUtils;

public class StudentDao {
	
	public QueryResult pageQuery(int startindex, int pagesize) {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		
		QueryResult qr = new QueryResult();
		try {
			conn = JdbcUtils.getConnection();
			String sql = "select * from student limit ?,?";
			st = conn.prepareStatement(sql);
			st.setInt(1, startindex);
			st.setInt(2, pagesize);
			rs = st.executeQuery();
			
			List<Student> list = new ArrayList<Student>();
			while (rs.next()) {
				Student s = new Student();
				s.setId(rs.getString("id"));
				s.setName(rs.getString("name"));
				list.add(s);
			}
			qr.setList(list);
			sql = "select count(*) from student";
			st = conn.prepareStatement(sql);
			rs = st.executeQuery();
			if (rs.next()) {
				qr.setTotalrecord(rs.getInt(1));
			}
			return qr;
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			JdbcUtils.release(conn, st, rs);
		}
	}
	
}

照理说,开发完数据访问层,一定要对程序已编写好的部分代码进行测试。但是我们有信心认为以上代码都不会有任何问题,这点自信都没有,搞鬼啊!

开发service层(service层对web层提供所有的业务服务)

在cn.liayun.service包下创建一个BusinessService类,该类的具体代码如下:

package cn.liayun.service;

import cn.liayun.dao.StudentDao;
import cn.liayun.domain.PageBean;
import cn.liayun.domain.QueryInfo;
import cn.liayun.domain.QueryResult;

public class BusinessService {
	
	public PageBean pageQuery(QueryInfo info) {
		StudentDao dao = new StudentDao();
		QueryResult qr = dao.pageQuery(info.getStartindex(), info.getPagesize());
		
		PageBean bean = new PageBean();
		bean.setCurrentpage(info.getCurrentpage());
		bean.setList(qr.getList());
		bean.setPagesize(info.getPagesize());
		bean.setTotalrecord(qr.getTotalrecord());
		
	 	return bean;
	}
	
}

同理,开发完业务逻辑层,一定要对程序已编写好的部分代码进行测试,但是我们有信心认为业务逻辑层的代码没有任何问题,所以我们略过测试这一步。

开发web层

开发学生信息的分页查询功能

在cn.liayun.utils包下创建一个WebUtils工具类,该工具类的功能就是封装客户端提交的表单数据到Student对象中。

package cn.liayun.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;

public class WebUtils {
	public static <T> T request2Bean(HttpServletRequest request, Class<T> beanClass) {
		try {
			T bean = beanClass.newInstance();
			//得到request里面的所有数据
			Map<String, String[]> map = request.getParameterMap();
			
			//注册一个日期转换器
			ConvertUtils.register(new Converter() {
				
				@Override
				public <T> T convert(Class<T> type, Object value) {
					if (value == null) {
						return null;
					}
					String str = (String) value;
					if (str.trim().equals("")) {
						return null;
					}
					SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
					try {
						return (T) df.parse(str);
					} catch (ParseException e) {
						throw new RuntimeException(e);
					}
				}
			}, Date.class);
			
			//map{name=liayun,password=123321,birthday=1995-10-01}	bean(name=liayun,password=123321)
			BeanUtils.populate(bean, map);
			return bean;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static String generateID() {
		return UUID.randomUUID().toString();
	}
}

接着就在cn.liayun.web.controller包中创建一个ListStudentServlet,用于处理学生分页请求。

package cn.liayun.web.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.liayun.domain.PageBean;
import cn.liayun.domain.QueryInfo;
import cn.liayun.service.BusinessService;
import cn.liayun.utils.WebUtils;

@WebServlet("/ListStudentServlet")
public class ListStudentServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		QueryInfo info = WebUtils.request2Bean(request, QueryInfo.class);
		BusinessService service = new BusinessService();
		PageBean bean = service.pageQuery(info);
		request.setAttribute("pagebean", bean);
		
		request.getRequestDispatcher("/liststudent.jsp").forward(request, response);
	}

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

}

接下来就要创建学生显示界面(liststudent.jsp)了,分页显示这一块,有很多细节需要我们注意,比如:

  • 当我们浏览第一页的数据时,上一页超链接就不能显示出来;当我们浏览尾页的数据时,下一页超链接也不能显示出来;
  • 当我们浏览到某一页时,页码条中的这一页就应该显示为普通文字,而不是超链接,即该页是无法点击再次查看的;
  • 除了点击上一页和下一页,我们还应可自由跳转到任何页面;
  • 我们还应可自由控制每页可显示的记录数。

下面我们就按照以上细节来创建学生显示界面(liststudent.jsp),listcustomer.jsp页面的内容为:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ 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>显示学生分页数据</title>
</head>
<body>

    <c:forEach var="s" items="${pagebean.list }">
        ${s.id }    ${s.name }<br/>
    </c:forEach>

    <script type="text/javascript">
        function gotopage(currentpage) {
            if ( currentpage < 1 || currentpage != parseInt(currentpage) || currentpage > ${pagebean.totalpage } ) {
                alert("请输入有效值!!!");
                document.getElementById("pagenum").value='';
            } else {
                var pagesize = document.getElementById("pagesize").value;
                window.location.href = '${pageContext.request.contextPath }/ListStudentServlet?currentpage='+currentpage+'&pagesize='+pagesize;
            }
        }

        function changesize(pagesize, oldvalue) {
            if ( pagesize < 0 || pagesize != parseInt(pagesize) ) {
                alert("请输入合法值!!!");
                document.getElementById("pagesize").value = oldvalue;
            } else {
            	// 当前页currentpage就不传过去了,也即一改变页面大小,由于没带当前页过去,所以就从第1页开始显示
                window.location.href = '${pageContext.request.contextPath }/ListStudentServlet?pagesize='+pagesize; 
            }
        }
    </script>

	共[${pagebean.totalrecord }]条记录,
	每页显示<input type="text" id="pagesize" value="${pagebean.pagesize }" onchange="changesize(this.value, ${pagebean.pagesize })" style="width:30px" maxlength="2">条,
	共[${pagebean.totalpage }]页,
	当前第[${pagebean.currentpage }]页
        
    <c:if test="${pagebean.currentpage!=1 }">
        <a href="javascript:void(0)" onclick="gotopage(${pagebean.previouspage })">上一页</a>
    </c:if>
    <c:forEach var="pagenum" items="${pagebean.pagebar }">
        <c:if test="${pagenum==pagebean.currentpage }">
            <font color="red">${pagenum }</font>
        </c:if>
        <c:if test="${pagenum!=pagebean.currentpage }">
            <a href="javascript:void(0)" onclick="gotopage(${pagenum })">${pagenum }</a>
        </c:if>
    </c:forEach>
    <c:if test="${pagebean.currentpage!=pagebean.totalpage }">
        <a href="javascript:void(0)" onclick="gotopage(${pagebean.nextpage })">下一页</a>
    </c:if>

    <input type="text" id="pagenum" style="width: 30px">
    <input type="button" value="GO" onclick="gotopage(document.getElementById('pagenum').value)">
</body>
</html>

至此,学生信息查询的分页练习就算完成了,测试结果如下:

Java实现查询工商信息存储到数据库中 javaweb实现查询功能_Java实现查询工商信息存储到数据库中_05