分页的分页加搜索功能技术演示

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33621967/article/details/53291833

针对上一版本,我们做的改进版!
做一个类似于百度分页的分页技术加上搜索功能(如下图)!
这里写图片描述



这里写图片描述



结果预览图:
这里写图片描述



这里写图片描述



这里写图片描述



代码实现:
前端技术
主页面(index.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>浏览器分页的分页演示</title>
  </head>

  <body>
    <!-- 使用c标签重写url的技术很强,穿透能力更强! -->
    <a href="<c:url value='/PageServlet' />">分页后的分页查询</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" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<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="<c:url value='/PageServlet?pageNo="+obj.value+"' />";
        }
    </script>

  </head>

  <body>
    <!-- 前端页面实现用到的技术:JSTL(c标签--很强!)+EL表达式 -->
    <!-- 下面是把所有的数据全部输出来了 -->
    <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="<c:url value='/PageServlet?pageNo=${result.currentPage-1}' />">
            上一页
        </a>
        &nbsp;
    </c:if>

    <!-- 分页的分页进行修改的地方就是这里---将已经拿到的页面进行分页操作! -->
    <c:forEach begin="${startN }" end="${endN }" var="idx">
        <!-- 用超链接进行包一下即可 -->
        <c:if test="${result.currentPage!=idx }">
            <!-- 这里记得将当前页的参数传参过去 -->
            <a href="<c:url value='/PageServlet?pageNo=${idx }' />">
                ${idx }
            </a>
        </c:if>
        <c:if test="${result.currentPage==idx }">
            ${idx }
        </c:if>
        &nbsp;
    </c:forEach>

    <!-- 在这个下面添加下一页的功能(添加这个功能之前还需要判断当前页面是否为最后一页,如果为最后一页则不显示下一页) -->
    <c:if test="${result.currentPage!=result.pageCount }">
        <a href="<c:url value='/PageServlet?pageNo=${result.currentPage+1}' />">
            下一页
        </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="<c:url value='/PageServlet' />" method="post">
        <img alt="图片不存在" src="<c:url value='/imgs/bd.gif' />">
        学号中包含:<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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> query(Integer pageNo,Person p) throws Exception {
        //dao层进行封装的数据包含:1)一共包含多少页面  2)所有行数据
        Map<String, Object> result = new HashMap<String, Object>();
        //首选计算出总页数
        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<Map<String, Object>> datas = run.query(sql_2, new MapListHandler());
        result.put("datas", datas);
        return result;
    }

}


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<Connection> t = new ThreadLocal<Connection>();

    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.Driver</property>
        <property name="jdbcUrl">
            <![CDATA[jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8]]>
        </property>
        <property name="user">root</property>
        <property name="password">1234</property>
        <!-- 初始化池大小 -->
        <property name="initialPoolSize">2</property>
        <!-- 最大空闲时间 -->
        <property name="maxIdleTime">30</property>
        <!-- 最多有多少个连接 -->
        <property name="maxPoolSize">10</property>
        <!-- 最少几个连接 -->
        <property name="minPoolSize">2</property>
        <!-- 每次最多可以执行多少个批处理语句 -->
        <property name="maxStatements">50</property>
    </default-config> 
    <!-- 命名的配置 -->
    <named-config name="demo">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">
            <![CDATA[jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8]]>
        </property>
        <property name="user">root</property>
        <property name="password">1234</property>
        <property name="acquireIncrement">5</property><!-- 如果池中数据连接不够时一次增长多少个 -->
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">15</property>
        <property name="maxStatements">0</property>
        <property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him -->
    </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 + "]";
    }

}

猜你喜欢

转载自blog.csdn.net/qq_33621967/article/details/53291833