针对上一版本,我们做的改进版!
做一个类似于百度分页的分页技术加上搜索功能(如下图)!
代码实现:
前端技术
主页面(index.jsp)
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>浏览器分页的分页演示title>
head>
<body>
<a href=" ">分页后的分页查询a>
body>
html>
前端页面最终结果页面效果显示(show.jsp):
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<style type="text/css">
table{
border: 1px solid red;
border-collapse: collapse;
width: 150px;
}
td{
border: 1px solid red;
}
style>
<title>分页结果页面title>
<script type="text/javascript">
function sub(obj){
window.location.href=" ";
}
script>
head>
<body>
<h2>分页后的分页查询技术演示h2>
<table>
<tr> <th>学号th> <th>姓名th> tr>
<c:forEach items="${result.datas}" var="map">
<tr> <td>${map.id}td> <td>${map.name }td> tr>
c:forEach>
table>
<hr/>
<c:if test="${result.currentPage!=1 }">
<a href=" ">
上一页
a>
c:if>
<c:forEach begin="${startN }" end="${endN }" var="idx">
<c:if test="${result.currentPage!=idx }">
<a href=" ">
${idx }
a>
c:if>
<c:if test="${result.currentPage==idx }">
${idx }
c:if>
c:forEach>
<c:if test="${result.currentPage!=result.pageCount }">
<a href=" ">
下一页
a>
c:if>
<br/><br/>
<select onchange="sub(this)">
<c:forEach begin="1" end="${result.pageCount }" var="idx">
<option <c:if test="${idx==result.currentPage }">selected="selected"c:if> value="${idx }">第${idx }页option>
c:forEach>
select>
<h2>模拟类似于百度的搜索功能h2>
<form action=" " method="post">
<img alt="图片不存在" src=" ">
学号中包含:<input type="text" name="id" value="${p.id }" />
姓名中包含:<input type="text" name="name" value="${p.name}" />
<input type="submit" value="百度一下" />
form>
body>
html>
后台技术
前端调用servlet层–(PageServlet.java)–MVC中的C–控制层
package cn.hncu.servlet;
import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hncu.domain.Person;
import cn.hncu.service.IPageService;
import cn.hncu.service.PageServiceImpl;
public class PageServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
// 注入service层
IPageService service = new PageServiceImpl();
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
// 作用:拿到前端页面的用户选择的页面面数
String pageNo = request.getParameter("pageNo");
if (pageNo == null || "".equals(pageNo.trim())) {// 用户第一次进入分页页面还没有进行选择页面的情况
pageNo = "1";
}
// 从servlet层将前台数据进行封装到domain值对象中去
// 判断用户的提交方式
Person p = null;
if (request.getMethod().equalsIgnoreCase("GET")) {// GET方式进行提交,防止用户直接回车
// 先看看session中有没有旧的查询条件值对象stud
p = (Person) request.getSession().getAttribute("p");
if (p == null) {
p = new Person();// 查全
}
} else {// POST方式提交
// 拿数据
p = new Person();
String id = request.getParameter("id");
String name = request.getParameter("name");
//是中文的话到数据库中就会乱码!----request.setCharacter("utf-8")即可解决从前端页面拿到的数据是中文乱码的问题;
p.setId(id);
p.setName(name);
request.getSession().setAttribute("p", p);
}
try {
// 将页面进行转换成整数的形式
int iPageNo = Integer.valueOf(pageNo);// 从前台页面拿到的数据!
Map result = service.query(iPageNo,p);
result.put("currentPage", iPageNo);// 将当前页面同样封装到集合中去!
/*
* 理一下:map集合中一共封装了三个数据:1)总页数--dao层封装 2)所有数据行信息--dao层封装
* 3)当前页数--servlet层进行封装
*/
// 演示分页的分页---三个数据应该从servlet层进行相应的封装!(一个startN-起始页,一个末尾页--endN,)
// 如果总页数少于一页中包含的行数数据及showSize,最后一行数据就等于pageCount
int startN = 0;
int endN = 0;
int showSize = 10;// 每页中包含的数据行数!
int pageCount = Integer.parseInt("" + result.get("pageCount"));
if (pageCount <= showSize) {
startN = 1;
endN = pageCount;
} else {// 否则的话就按照规律进行页面的数据分配----在这里我们采用百度的分页原理
// 计算起始页号
if (iPageNo <= (showSize / 2)) {
startN = 1;// 起始行数还是不变的
} else {
startN = iPageNo - (showSize / 2);
}
// 计算终止页号
endN = startN + (showSize - 1);
// 判断终止页号是否已经超过了总页号
if (endN > pageCount) {
endN = pageCount;
startN = endN - (showSize - 1);
}
}
// 将起始页和终止页添加到容器中并发送到前端页面
request.setAttribute("startN", startN);
request.setAttribute("endN", endN);
// 数据封装完之后必须记得添加到容器中!
request.setAttribute("result", result);
// 转发到前台页面进行相应的显示!
request.getRequestDispatcher("/jsps/show.jsp").forward(request,
response);
} catch (NumberFormatException e) {
response.getWriter().println("页面格式转换错误!");
} catch (Exception e) {
response.getWriter().println("数据库查询错误!");
}
}
}
servlet层调用service层(接口–IPageService.java)
package cn.hncu.service;
import java.util.Map;
import cn.hncu.domain.Person;
public interface IPageService {
public abstract Map query(Integer pageNo,Person p) throws Exception;
}
实现类(PageServiceImpl.java)
package cn.hncu.service;
import java.util.Map;
import cn.hncu.dao.PageDAO;
import cn.hncu.dao.PageDAOJdbc;
import cn.hncu.domain.Person;
public class PageServiceImpl implements IPageService {
//以现在的技术还是只能够依赖注入,等学到后面就就可以更高级的方法弄了-----注入dao层
PageDAO dao = new PageDAOJdbc();
@Override
public Map query(Integer pageNo,Person p) throws Exception {
return dao.query(pageNo,p);
}
}
service层调用DAO层(接口PageDAO)
package cn.hncu.dao;
import java.util.Map;
import cn.hncu.domain.Person;
public interface PageDAO {
public abstract Map query(Integer pageNo,Person p) throws Exception;
}
实现类(PageDAOJdbc.java)
package cn.hncu.dao;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import cn.hncu.domain.Person;
import cn.hncu.pubs.C3p0Utils;
public class PageDAOJdbc implements PageDAO {
@Override
public Map query(Integer pageNo,Person p) throws Exception {
//dao层进行封装的数据包含:1)一共包含多少页面 2)所有行数据
Map result = new HashMap();
//首选计算出总页数
int pageSize = 10;
//构造条件查询的sql,包含两条,一条用于查询总行数,另一条查数据行
String sql_1 = "select count(1) from person where 1=1";//查询总行数
String sql_2 = "select * from person where 1=1";//查询当前页要显示的内容(数据行)
if(p.getId()!=null && !p.getId().trim().equals("")){
sql_1 = sql_1 + " and id like '%"+p.getId().trim()+"%'";
sql_2 = sql_2 + " and id like '%"+p.getId().trim()+"%'";
}
if(p.getName()!=null && !p.getName().trim().equals("")){
sql_1 = sql_1 + " and name like '%"+p.getName().trim()+"%'";
sql_2 = sql_2 + " and name like '%"+p.getName().trim()+"%'";
}
System.out.println("sql_1:"+sql_1);
QueryRunner run = new QueryRunner(C3p0Utils.getDataSource());
Object obj = run.query(sql_1, new ScalarHandler());
//转换成整数
int rows = Integer.valueOf(String.valueOf(obj));//拿到总行数
//根据总行数计算出纵页数
int pageCount = rows/pageSize +(rows%pageSize==0?0:1);//页数
//添加到集合中去
result.put("pageCount", pageCount);
int startN = (pageNo-1)*pageSize;
sql_2 = sql_2 + " limit " + startN +","+pageSize;
System.out.println("sql_2:"+sql_2);
//封装所有行数据
List
DAO访问数据库操作!在这里我就不演示数据库了……
针对上面的基本框架存在的一些小细节还有将框架之间的连接需要的东西!
第一个补的地方:
DAO层访问数据库需要用到C3p0的一个工具类:
C3p0Utils.java
package cn.hncu.pubs;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3p0Utils {
//本地线程管理对象,用于实现: 同一个线程获取的连接是同一个
private static ThreadLocal t = new ThreadLocal();
private static DataSource pool =null;
static{
try {
//配置文件和当前类放在一起
pool = new ComboPooledDataSource();//使用默认配置项
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDataSource(){
return pool;
}
public static Connection getConn() {
//先从t中拿,如果有就拿出去,如果没有再到池中拿且把该对象放到t中
Connection con = t.get();
if(con==null){
try {
con = pool.getConnection();
t.set(con); //放到t中
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
System.out.println("获取一个连接:"+con.hashCode());
return con;
}
}
跟随的一个配置文件(c3p0-config.xml):
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl">
property>
<property name="user">rootproperty>
<property name="password">1234property>
<property name="initialPoolSize">2property>
<property name="maxIdleTime">30property>
<property name="maxPoolSize">10property>
<property name="minPoolSize">2property>
<property name="maxStatements">50property>
default-config>
<named-config name="demo">
<property name="driverClass">com.mysql.jdbc.Driverproperty>
<property name="jdbcUrl">
property>
<property name="user">rootproperty>
<property name="password">1234property>
<property name="acquireIncrement">5property>
<property name="initialPoolSize">10property>
<property name="minPoolSize">5property>
<property name="maxPoolSize">15property>
<property name="maxStatements">0property>
<property name="maxStatementsPerConnection">5property>
named-config>
c3p0-config>
再用到上面的工具类时跟随的有几个相应的包记得导入进来!!!
第二个补的地方:
在DAO层需要进行访问数据库中的数据进行条件选择时(为了搜索!)
建立值对象将servlet层的数据(拿前端的数据)封装到domain(值对象中),然后DAO层进行读取!
domain(值对象–person.java)
package cn.hncu.domain;
public class Person {
private String id;
private String name;
public Person() {
}
public Person(String id, String name) {
this.id = id;
this.name = 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;
}
@Override
public String toString() {
return "Pseron [id=" + id + ", name=" + name + "]";
}
}