摘要:前言给大家讲解全栈通用分页查询码字不易,点个关注转载请说明开发工具思维导图目录一所需要的包二后端数据库帮助类通用查询分页父类书籍层类分页工具类三前端文件助手类前端界面四一所需要的包二后端数据库
前言:给大家讲解全栈通用分页查询
码字不易,点个关注
转载请说明!
开发工具:eclipse
思维导图:
目录
DBAccess—数据库助手类
package com.hpw.util;import java.io.InputStream;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 DBAccess { private static String driver; private static String url; private static String user; private static String password; static {// 静态块执行一次,加载 驱动一次 try { InputStream is = DBAccess.class .getResourceAsStream("config.properties"); Properties properties = new Properties(); properties.load(is); driver = properties.getProperty("driver"); url = properties.getProperty("url"); user = properties.getProperty("user"); password = properties.getProperty("pwd"); Class.forName(driver); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 获得数据连接对象 * * @return */ public static Connection getConnection() { try { Connection conn = DriverManager.getConnection(url, user, password); return conn; } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } public static void close(ResultSet rs) { if (null != rs) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } } public static void close(Statement stmt) { if (null != stmt) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } } public static void close(Connection conn) { if (null != conn) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } } public static void close(Connection conn, Statement stmt, ResultSet rs) { close(rs); close(stmt); close(conn); } public static boolean isOracle() { return "oracle.jdbc.driver.OracleDriver".equals(driver); } public static boolean isSQLServer() { return "com.microsoft.sqlserver.jdbc.SQLServerDriver".equals(driver); } public static boolean isMysql() { return "com.mysql.cj.jdbc.Driver".equals(driver); } public static void main(String[] args) { Connection conn = DBAccess.getConnection(); System.out.println(conn); DBAccess.close(conn); System.out.println("isOracle:" + isOracle()); System.out.println("isSQLServer:" + isSQLServer()); System.out.println("isMysql:" + isMysql()); System.out.println("数据库连接(关闭)成功"); }}
这里是对我们定义的XML文件进行解析来决定数据源,相比于之前定义的DBHelper类适用范围更广。
对应的dtl文件
#oracle9i#driver=oracle.jdbc.driver.OracleDriver#url=jdbc:oracle:thin:@localhost:1521:ora9#user=test#pwd=test#sql2005#driver=com.microsoft.sqlserver.jdbc.SQLServerDriver#url=jdbc:sqlserver://localhost:1423;DatabaseName=test#user=sa#pwd=sa#sql2000#driver=com.microsoft.jdbc.sqlserver.SQLServerDriver#url=jdbc:microsoft:sqlserver://localhost:1433;databaseName=unit6DB#user=sa#pwd=888888#mysql8driver=com.mysql.cj.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/mybatis_ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&useSSL=trueuser=rootpwd=123456#mysql5#driver=com.mysql.jdbc.Driver#url=jdbc:mysql://127.0.0.1:3306/mybatis_ssm?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT&useSSL=true#user=root#pwd=pppppp
EncodingFiter—编码过滤类
package com.hpw.util;import java.io.IOException;import java.util.Iterator;import java.util.Map;import java.util.Set;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * 中文乱码处理 * */public class EncodingFiter implements Filter { private String encoding = "UTF-8";// 默认字符集 public EncodingFiter() { super(); } public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; // 中文处理必须放到 chain.doFilter(request, response)方法前面 res.setContentType("text/html;charset=" + this.encoding); if (req.getMethod().equalsIgnoreCase("post")) { req.setCharacterEncoding(this.encoding); } else { Map map = req.getParameterMap();// 保存所有参数名=参数值(数组)的Map集合 Set set = map.keySet();// 取出所有参数名 Iterator it = set.iterator(); while (it.hasNext()) { String name = (String) it.next(); String[] values = (String[]) map.get(name);// 取出参数值[注:参数值为一个数组] for (int i = 0; i < values.length; i++) { values[i] = new String(values[i].getBytes("ISO-8859-1"), this.encoding); } } } chain.doFilter(request, response); } public void init(FilterConfig filterConfig) throws ServletException { String s = filterConfig.getInitParameter("encoding");// 读取web.xml文件中配置的字符集 if (null != s && !s.trim().equals("")) { this.encoding = s.trim(); } }}
package dao;import java.lang.reflect.Field;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;import com.hpw.util.DBAccess;import com.hpw.util.PageBean;import com.hpw.util.StringUtils;import entity.Book;public class BaseDao { /** * 所有Dao层的父类 提供解决方案 1.抽取变化部分作为参数 sql ,Class对象 结果集 2.抽取公共的父类,把重复性的代码剥离出来 * * @param */ public List keylist(String sql, Class clz) throws Exception { // 不能确定集合装什么东西 // 子类Dao继承BaseDao子类传递什么类.class,那么集合中放到就是什么 List list = new ArrayList(); Connection con = DBAccess.getConnection(); PreparedStatement ps = con.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while (rs.next()) { /** * 代码不一样 具体体现在 不同的表有不同字段 那么实体类对应的属性就会不一样 * * 1.实例化了一个对象 2.从ResultSet的对象的属性获取值(bid)获取值赋值给了前面的实例化对象 3.把已经赋值了的对象 ,添加到集合中 */ T t = clz.newInstance(); Field[] fields = clz.getDeclaredFields(); for (Field f : fields) { f.setAccessible(true); f.set(t, rs.getObject(f.getName())); } list.add(t); } return list; } /** * 通用的分页查询 * * @param sql * @param clz * @return * @throws Exception */ public List executeQuery(String sql, Class clz ,PageBean pageBean) throws Exception { List list = new ArrayList(); Connection con = DBAccess.getConnection(); PreparedStatement ps = null; ResultSet rs = null; /* * 是否需要分页? * 无需分页 (项目中的下拉框,查询条件教员下拉框 无需分页) * 必须分页(项目中列表类需求,订单列表,商品列表,学生列表) */ if(pageBean != null && pageBean.isPagination()) { String countSQL = getcountSQL(sql); ps = con.prepareStatement(countSQL); rs = ps.executeQuery(); if(rs.next()) { pageBean.setTotal(String.valueOf(rs.getObject(1))); } //挪动到下面,是因为最后才处理返回的结果集 //必须分页(列表需求) // *-- sql=SELECT * FROM t_mvc_book WHERE bname like "%圣墟%" // -- pagesql=sql limit (page-1)*rows,rows 对应某一页的数据 // -- countsql=select COUNT(1) from (sql)t; 符合条件的总记录数 String pageSQL = getpageSQL(sql,pageBean);//符合条件的某一页数据 ps = con.prepareStatement(pageSQL); rs = ps.executeQuery(); }else { //不分页(select需求) ps = con.prepareStatement(sql);//符合条件的所有数据 rs = ps.executeQuery(); } while (rs.next()) { T t = clz.newInstance(); Field[] fields = clz.getDeclaredFields(); for (Field f : fields) { f.setAccessible(true); f.set(t, rs.getObject(f.getName())); } list.add(t); } return list; } /** * 将原生sql转换成countsql * @param sql * @return */ private String getcountSQL(String sql) { //countsql=select COUNT(1) from (sql)t;符合条件的总记录数 return "select count(1) from ("+sql+") t"; } /** * 将原生SQL转换成pageSQL * @param sql * @param pageBean * @return */ private String getpageSQL(String sql,PageBean pageBean) { //(this.page - 1) * this.rows; //sql:原生sql (page-1)*rows:起始下标 rows:多少页 //pagesql=sql limit (page-1)*rows,rows return sql +" limit "+ pageBean.getStartIndex() +","+pageBean.getRows(); }}
package dao;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import com.hpw.util.DBAccess;import com.hpw.util.PageBean;import com.hpw.util.StringUtils;import entity.Book;public class BookDao extends BaseDao{ /** * * 简单的查询方法 (思路) * 1.建立数据库连接 * 2.预定义对象PrepareStatement * 3.查询结果集 * 4.处理结果集 * * 不足之处 * 换一张表查询 t_jsoup_article * 1.以上三步 (建立数据库连接 ,预定义对象PrepareStatement,查询结果集 )都是重复的 * 2.都是返回数据库表对应的集合 * 3.都是要处理结果集 ResultSet rs * 代码不一样 具体体现在 不同的表有不同字段 那么实体类对应的属性就会不一样 * * 总结:需要写大量的重复代码 , 系统中的查询功能越多 重复代码量越大 * * 提供解决方案 * 1.抽取变化部分作为参数 * sql ,Class对象 结果集 * 2.抽取公共的父类,把重复性的代码剥离出来 */ public List keylist(Book book) throws Exception { List book1 = new ArrayList(); String sql = "select * from t_mvc_book where 1=1"; // 书籍名称 String bname = book.getBname(); // 书籍名称模糊查询 是前台jsp界面传数据 if (StringUtils.isNotBlank(bname)) { sql += " and bname like "%" + bname + "%" "; } Connection con = DBAccess.getConnection(); PreparedStatement ps = con.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while (rs.next()) { book1.add(new Book(rs.getInt("bid"), rs.getString("bname"), rs.getFloat("price"))); } return book1; } public List list2(Book book) throws Exception{ String sql = "select * from t_mvc_book where 1=1"; // 书籍名称 String bname = book.getBname(); // 书籍名称模糊查询 是前台jsp界面传数据 if (StringUtils.isNotBlank(bname)) { sql += " and bname like "%" + bname + "%" "; } return super.keylist(sql, Book.class); } /** * 测试通用分页查询 * @param book * @param pageBean * @return * @throws Exception */ public List list3(Book book,PageBean pageBean) throws Exception{ String sql = "select * from t_mvc_book where 1=1"; // 书籍名称 String bname = book.getBname(); // 书籍名称模糊查询 是前台jsp界面传数据 if (StringUtils.isNotBlank(bname)) { sql += " and bname like "%"+bname+"%""; } return super.executeQuery(sql, Book.class, pageBean); } /** * 思考: * 在项目中大量的出现分页的需要(订单列表,商品列表,学生列表...) * 目标: * 想要做一个通用的分页查询,子类去继承父类,自带了分页功能,并且代码量极少; * 最终当碰到分页的需求的时候,只要写少量的代码 * 实现: * mysql分页 * 分页通常有关键的元素 第n页 、显式数目(rows)、符合条件的总记录数(total) *-- sql=SELECT * FROM t_mvc_book WHERE bname like "%圣墟%" -- pagesql=sql limit (page-1)*rows,rows -- countsql=select COUNT(1) from (sql)t; * * 编码: * 2.1原先List集合中返回的是符合条件的所有数据,现在我需要发挥第page页的数据 * 那么意味着sql要加工成pageSql * 2.2需要分页,那么要求出符合条件的总记录数,保存到pagebean中,意味着sql要加工成countSql * 共85条数据 1页10条 总共9页 共70条数据 1页10条 总共7页 通过上面的数字,说明了要得出共n页,那么必须求出总记录数 共n页的算法 : total % rows == 0 ? total / rows :total / rows +1; */ public static void main(String[] args) throws Exception { BookDao bd = new BookDao(); Book book = new Book(); book.setBname("圣墟"); //List list = bd.keylist(book); //List list = bd.list2(book); PageBean pageBean = new PageBean(); //查第二页的数据 模拟从jsp传递页码2到后台 //pageBean.setPage(2); //项目开发中 下拉框的需求 不分页 模拟从jsp传递 不分页的信息pagination=false pageBean.setPagination(false); List list = bd.list3(book, pageBean); for (Book book2 : list) { System.out.println(book2); } }}
在父类中对key进行非空判断是为了判断用户是否在输入框中输入值进行查询,如果点击下一页之类的操作,key是上一次查询请求的值,改变的只是页码参数,由PageBean这个类对上一次请求参数进行保存。
package com.hpw.util;import java.io.StringBufferInputStream;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletRequest;import com.sun.net.httpserver.HttpServer;/** * 分页工具类 * */public class PageBean { private int page = 1;// 页码 private int rows = 10;// 页大小 private int total = 0;// 总记录数 private boolean pagination = true;// 是否分页 private String url;// 保存上一次请求的URL private Map paramMap = new HashMap();// 保存上一次请求的参数 /** * 初始化pagebean ,保存上一次请求的重要参数 */ public void setRequest(HttpServletRequest req) { // 1.1需要保存上一次请求的URL this.setUrl(req.getRequestURL().toString()); // 1.2需要保存上一次请求的参数 this.setParamMap(req.getParameterMap()); // 1.3需要保存上一次请求的分页设置 this.setPagination(req.getParameter("pagination")); // 1.4需要保存上一次请求的展示条数 this.setRows(req.getParameter("rows")); // 1.5初始化的页码 this.setPage(req.getParameter("page")); } public void setPage(String page) { // TODO Auto-generated method stub if(StringUtils.isNotBlank(page)) { this.setPage(Integer.valueOf(page)); } } public void setRows(String rows) { // TODO Auto-generated method stub if(StringUtils.isNotBlank(rows)) { this.setRows(Integer.valueOf(rows)); } } public void setPagination(String pagination) { // TODO Auto-generated method stub// 只有在前台jsp填写了pagination=false,才代表不分页 if(StringUtils.isNotBlank(pagination)) { this.setPagination(!"false".equals(pagination)); } } public void setPagination(boolean pagination) { this.pagination = pagination; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Map getParamMap() { return paramMap; } public void setParamMap(Map paramMap) { this.paramMap = paramMap; } public PageBean() { super(); } public int getPage() { return page; } public void setPage(int page) { this.page = page; } public int getRows() { return rows; } public void setRows(int rows) { this.rows = rows; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public void setTotal(String total) { this.total = Integer.parseInt(total); } public boolean isPagination() { return pagination; } /** * 获得起始记录的下标 * * @return */ public int getStartIndex() { return (this.page - 1) * this.rows; } /** * 最大页 * * @return */ public int maxPage() { return this.total % this.rows == 0 ? this.total / this.rows : this.total / this.rows + 1; } /** * 下一页 */ public int nextPage() { // 如果当前页小于最大页,那就下一页为当前页加一,如果不小于,说明当前页就是最大页,那就无需加一 return this.page < this.maxPage() ? this.page + 1 : this.page; } /** * 上一页 * * @return */ public int previousPage() { return this.page > 1 ? this.page - 1 : this.page; } @Override public String toString() { return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination + "]"; }}
有了前端通用分页,在每一个页面中如果需要分页,仅仅需要在jsp界面中编写我们自己定义好的分页标签。将重复代码都提取到了标签助手类中。
hpw 1.1 core library hpw core 1.1 hpw http://hpw11.myjsp page com.hpw.tag.pageTag JSP pageBean true true
package com.hpw.tag;import java.io.IOException;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import javax.servlet.jsp.JspException;import javax.servlet.jsp.JspWriter;import javax.servlet.jsp.tagext.BodyTagSupport;import com.hpw.util.PageBean;public class pageTag extends BodyTagSupport { private PageBean pageBean;// 包含了所有分页相关的元素 public PageBean getPageBean() { return pageBean; } public void setPageBean(PageBean pageBean) { this.pageBean = pageBean; } @Override public int doStartTag() throws JspException { // TODO Auto-generated method stub // 没有标签体,要输出内容 JspWriter out = pageContext.getOut(); try { out.print(toHTML()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } return super.doStartTag(); } private String toHTML() { StringBuffer sb = new StringBuffer(); // 隐藏的form表单 这个就是上一次请求下次重新发的奥义所在 sb.append(" "); // 分页条 sb.append(" "); // 分页执行的jsp代码 sb.append(""); return sb.toString(); }}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@taglib uri="http://hpw11.myjsp" prefix="p"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>书籍列表 书籍ID 书籍名 价格 ${b.bid } ${b.bname } ${b.price }
新增
效果展示:
下面的分页在jsp界面仅用一行就能完成,其他界面还需要也一样,不用每个界面再写HTML和JS来实现这个分页条的效果!重复代码。能有这些效果完全少不了PageBean对象!!!
package com.hpw.web;import java.io.IOException;import java.util.List;import java.util.Map;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 com.hpw.util.PageBean;import dao.BookDao;import entity.Book;@WebServlet("/book/search")public class BookServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /** * 目标: * 痛点:每次做分页需求的时候,都会有大量的重复的后台代码,以及前台代码 * 后台代码重复问题已解决 * 前台重复代码问题 * 1.大量的前台html重复 * 2.大量的javaScript代码 * 目标: * 定义一个标签 * * 无需写任何的html以及js,就可以完成前端分页 * 分析: * 1. 前台分页 后一次请求相较于上一次只不过是页码改变了 * 1.1需要保存上一次请的的URL * 1.2需要保留上一次请求的参数 * 1.3需要保存上一页的分页设置 pagination * 1.4需要保存上一次的展示条目数 * 1.5初始化请求的页码 page * 2.开发自定义jsp标签(page标签) * 定义pagebean 因为pagebean中包含了分页中所有的元素 (page/rows/pagination/total/nexPage/previouPage/maxPage) * * 前台jsp传递书名圣墟 , 后台接收 req.getParameter("bname") * 爱好:传递一个数组 蓝球,足球...hobby String[] hobbys = req.getParameterValues("") * * bname String 这个数组长度是为1的 * hobby String [] 可能会有很多个 * ... * 本方法的作用是接收jsp页面传递到后台的参数值键值对,也就是把parameteMap遍历,可以拿到bname以及hobby Map parameteMap = req.getParameterMap(); */ BookDao bookDao=new BookDao(); Book book=new Book(); book.setBname(req.getParameter("bname")); PageBean pageBean=new PageBean(); pageBean.setRequest(req); try { List list3 = bookDao.list3(book, pageBean); req.setAttribute("books", list3); req.setAttribute("pageBean", pageBean); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } req.getRequestDispatcher("/index.jsp").forward(req, resp); //本方法的作用是接收jsp页面传递到后台的参数值键值对,也就是把parameteMap遍历,可以拿到bname以及hobby// Map parameteMap = req.getParameterMap(); }}
前端用户发送请求进过我们的一系列处理之后返回一个符合用户请求的前端页面呈现!!!带着这个流程去查看学习对应地方的代码。
这里的核心是PageBean,它几乎每个流程都在,它由用户需求决定,然后决定数据,再决定分页条!!!
到这里就结束了,我依旧是那个学IT的小学生
欢迎大佬指点
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119210.html
摘要:通用是为了解决使用中的基本操作,使用它可以很方便的进行开发,可以节省开发人员大量的时间。当该参数设置为时,时会查询第一页,超过总数时,会查询最后一页。 SpringBoot 是为了简化 Spring 应用的创建、运行、调试、部署等一系列问题而诞生的产物,自动装配的特性让我们可以更好的关注业务本身而不是外部的XML配置,我们只需遵循规范,引入相关的依赖就可以轻易的搭建出一个 WEB 工...
摘要:但能拷贝图粘贴后不失真通常是收费富文本编辑器才具备的能力。是否支持编程语言高亮,例如按,语言高亮是否支持数学公式等等因此选择了两款富文本编辑器,支持截屏粘贴,当做跟踪系统时这个功能特别有用。 一、Web应用技术栈 在开发Web应用时,通常会使用到以下技术栈: showImg(https://segmentfault.com/img/bVbwceG);对应这些技术栈都已有相应的开源产品...
摘要:代码自动生成底层服务有很多通用的,利用代码生成最好不过了,这里作者将代码生成放在中的,避免与正式代码冲突。主要通过来实现,项目中的模板文件可以自行定义。相互学习,共同进步 从零开始学习Spring Boot也有几天时间了,项目已经不允许我这么慢慢学习了,急需底层变现实现一套简单的Restful API用于业务支撑。 于是在GitHub上找到了一个不错的demo,直接看demo搭建自己的...
摘要:前端一种新一代高性能全栈开发实践背景本项目将使用配合最简单的逻辑来展示一个基于的全新一代高性能全栈开发实践的为什么是对于为何不是等著名框架,或许可能很多人会产生疑惑,本身和非常的相似,而它的出现,不仅是大大改进过去时代性能低下通病,外加配 SanicCRUD-vue Sanic + 前端MVVM 一种新一代Python高性能全栈开发实践showImg(https://segmentfa...
摘要:前端一种新一代高性能全栈开发实践背景本项目将使用配合最简单的逻辑来展示一个基于的全新一代高性能全栈开发实践的为什么是对于为何不是等著名框架,或许可能很多人会产生疑惑,本身和非常的相似,而它的出现,不仅是大大改进过去时代性能低下通病,外加配 SanicCRUD-vue Sanic + 前端MVVM 一种新一代Python高性能全栈开发实践showImg(https://segmentfa...
阅读 3135·2021-11-23 09:51
阅读 656·2021-10-14 09:43
阅读 3156·2021-09-06 15:00
阅读 2387·2019-08-30 15:54
阅读 2539·2019-08-30 13:58
阅读 1797·2019-08-29 13:18
阅读 1345·2019-08-27 10:58
阅读 477·2019-08-27 10:53