J2EE之通用分页知识(下)(详解)

简介: J2EE之通用分页知识(下)(详解)

前言

在前面J2EE之通用分页知识(上)中我们了解了通用分页知识的后端知识部分,今天我来给大家分享通用分页知识(下),主要是在前端jsp文件使用分页标签达到分页效果。接下来跟着思维导图一起来了解学习一下吧。

1. 了解分页思想

1.1 理论概念:

  • 分页思想指的是将大量的内容或数据分割成多个页面或部分,以便更好地管理和呈现信息。这种思想被广泛应用于书籍、网页、应用程序和其他形式的信息展示中。
  • 分页思想是一种通过将内容或数据分割成多个页面或部分,以便更好地组织、浏览和呈现信息的方式。它通过提供更好的导航和用户体验,改善性能和加载速度。

1.2 网页设计中的分页思想:

在网页设计和应用程序开发中,分页思想同样重要。将长页面分割成更小的部分可以提供更好的导航和用户体验。例如,在一个新闻网站上,将新闻文章分成多个页面可以使用户更容易浏览和定位感兴趣的内容。

1.3 案例说明分页思想

第一次查询:

在输入框输入"圣墟"点击查询,那么后台分页要传输拿到的参数如下

1.bname=圣墟 (查询的内容) 2.page=1 (显示的页数)

3.rows=10 (一页显示的数据数) 4.pagination=true (是否使用分页功能 true:使用;false:不使用)

5.url:http://localhost:8080/YX_PageBean01/book.action(f访问的网络路径)

第二次查询:(下一页)

在输入框输入"圣墟"点击查询,那么后台分页要传输拿到的参数如下

1.bname=圣墟 (查询的内容) 2.page=2(显示的页数)

3.rows=10 (一页显示的数据数) 4.pagination=true (是否使用分页功能 true:使用;false:不使用)

5.url:http://localhost:8080/YX_PageBean01/book.action(f访问的网络路径)

总之,相对于上一次请求,只是页码改变了(page),其他的查询条件不变。

第三次查询(尾页)

1.bname=圣墟 (查询的内容) 2.page=最大页数(显示的页数)

3.rows=10 (一页显示的数据数) 4.pagination=true (是否使用分页功能 true:使用;false:不使用)

5.url:http://localhost:8080/YX_PageBean01/book.action(f访问的网络路径)

总之,相对于上一次请求,只是页码改变了(page),其他的查询条件不变。

总结:

也就是说,相对于上一次请求,只是页码改变了(page),其他的查询条件不变。

2. 优化之前的PageBean类

PageBean类(代码如下)
package com.YX.Page.untils;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.coyote.http11.Http11AprProtocol;
/**
 * 分页工具类
 * 用于实现分页显示的工具类
 *@author 君易--鑨
 */
public class PageBean {
  private int page = 1;// 页码
  private int rows = 10;// 页大小
  private int total = 0;// 总记录数
  private boolean pagination = true;// 是否分页
  /**
   * 计算最大页数的方法
   * @return int 
   */
  public int maxPage() {
    return this.total % this.rows==0?
        this.total / this.rows :
          this.total / this.rows+1;
  }
  /***
   * 下一页的方法
   * @return
   */
  public int nextPage() {
    return this.page<this.maxPage() ?
        this.page+1 : this.page;
  }
  /**
   * 上一页的方法
   * @return
   */
  public int prevPage() {
    return this.page > 1 ? this.page-1 : this.page;
  }
  public void setRequest(HttpServletRequest req) {
//    初始化默认查询的第几页数据
    this.setPage(req.getParameter("page"));
//    初始化默认显示数据量
    this.setRows(req.getParameter("rows"));
//    初始化下拉框
    this.setPagination(req.getParameter("pagination"));
//    保留上一次的URL
    this.setUrl(req.getRequestURL().toString());
//          保留携带的参数
    this.setParamMap(req.getParameterMap());
  }
  /**
   * 设置初始化是否使用分页的方法
   * @param pagination
   */
  private void setPagination(String pagination) {
    if (StringUtils.isNotBlank(pagination)) ;
    this.setPagination(!"false".equals(pagination));
  }
  /**
   * 设置初始化默认显示数据量的方法
   * @param rows
   */
  public void setRows(String rows) {
    if (StringUtils.isNotBlank(rows)) 
    this.setRows(Integer.valueOf(rows));
  }
  /**
   * 设置初始化默认查询的第几页数据的方法
   * @param page
   */
  public void setPage(String page) {
    if (StringUtils.isNotBlank(page)) 
    this.setPage(Integer.valueOf(page));
  }
  private String url;//保留上一次发送请求的地址
  private Map<String, String[]> paramMap;//保留上一次发送请求携带的参数
  public String getUrl() {
    return url;
  }
  public void setUrl(String url) {
    this.url = url;
  }
  public Map<String, String[]> getParamMap() {
    return paramMap;
  }
  public void setParamMap(Map<String, String[]> 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;
  }
  public void setPagination(boolean pagination) {
    this.pagination = pagination;
  }
  /**
   * 获得起始记录的下标
   * 
   * @return
   */
  public int getStartIndex() {
    return (this.page - 1) * this.rows;
  }
  @Override
  public String toString() {
    return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination + "]";
  }
}

3.制定分页自定义jsp标签

3.1 创建PageTag类

package com.YX.Page.Tag;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;
import com.YX.Page.untils.PageBean;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
/**
 * @author 君易--鑨
 * 
 */
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 {
    JspWriter out = pageContext.getOut();
    try {
      out.print(toHTML());
    } catch (IOException e) {
      e.printStackTrace();
    }
    return SKIP_BODY;
  }
  private String toHTML() {
    StringBuilder sb = new StringBuilder();
    // 这里拼接的是一个上一次发送的请求以及携带的参数,唯一改变的就是页码
    sb.append("<form id='pageBeanForm' action='" + pageBean.getUrl() + "' method='post'>");
    // sb.append("<input type='hidden' name='methodName' value='list'>");
    sb.append("<input type='hidden' name='page'>");
    // 重要设置拼接操作,将上一次请求参数携带到下一次
    Map<String, String[]> paMap = pageBean.getParamMap();
    if (paMap != null && paMap.size() > 0) {
      Set<Map.Entry<String, String[]>> entrySet = paMap.entrySet();
      for (Map.Entry<String, String[]> entry : entrySet) {
        for (String val : entry.getValue()) {
          if (!"page".equals(entry.getKey())) {
            sb.append("<input type='hidden' name='" + entry.getKey() + "' value='" + val + "'>");
          }
        }
      }
    }
    sb.append("</form>");
    int page = pageBean.getPage();// 显示的页数
    int max = pageBean.maxPage();// 最大的页码数
    int before = page > 4 ? 4 : page - 1;// 当前选中页码前面的页码数
    int after = 10 - 1 - before;// 当前选中页码后面的页码数
    after = page + after > max ? max - page : after;
    // disabled
    boolean startFlag = page == 1;
    boolean endFlag = max == page;
    // 拼接分页条
    sb.append("<ul class='pagination'>");
    sb.append("<li class='page-item " + (startFlag ? "disabled" : "")
        + "'><a class='page-link' href='javascript:gotoPage(1)'>首页</a></li>");
    sb.append("<li class='page-item " + (startFlag ? "disabled" : "")
        + "'><a class='page-link' href='javascript:gotoPage(" + pageBean.prevPage() + ")'>&lt;</a></li>");
    // 代表了当前页的前4页
    for (int i = before; i > 0; i--) {
      sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page - i) + ")'>"
          + (page - i) + "</a></li>");
    }
    sb.append("<li class='page-item active'><a class='page-link' href='javascript:gotoPage(" + pageBean.getPage()
        + ")'>" + pageBean.getPage() + "</a></li>");
    // 代表了当前页的后5页
    for (int i = 1; i <= after; i++) {
      sb.append("<li class='page-item'><a class='page-link' href='javascript:gotoPage(" + (page + i) + ")'>"
          + (page + i) + "</a></li>");
    }
    sb.append("<li class='page-item " + (endFlag ? "disabled" : "")
        + "'><a class='page-link' href='javascript:gotoPage(" + pageBean.nextPage() + ")'>&gt;</a></li>");
    sb.append("<li class='page-item " + (endFlag ? "disabled" : "")
        + "'><a class='page-link' href='javascript:gotoPage(" + pageBean.maxPage() + ")'>尾页</a></li>");
    sb.append(
        "<li class='page-item go-input'><b>到第</b><input class='page-link' type='text' id='skipPage' name='' /><b>页</b></li>");
    sb.append("<li class='page-item go'><a class='page-link' href='javascript:skipPage()'>确定</a></li>");
    sb.append("<li class='page-item'><b>共" + pageBean.getTotal() + "条</b></li>");
    sb.append("</ul>");
    // 拼接分页的js代码
    sb.append("<script type='text/javascript'>");
    sb.append("function gotoPage(page) {");
    sb.append("document.getElementById('pageBeanForm').page.value = page;");
    sb.append("document.getElementById('pageBeanForm').submit();");
    sb.append("}");
    sb.append("function skipPage() {");
    sb.append("var page = document.getElementById('skipPage').value;");
    sb.append("if (!page || isNaN(page) || parseInt(page) < 1 || parseInt(page) > " + max + ") {");
    sb.append("alert('请输入1~N的数字');");
    sb.append("return;");
    sb.append("}");
    sb.append("gotoPage(page);");
    sb.append("}");
    sb.append("</script>");
    return sb.toString();
  }
}

3.2 创建YXmvc.tld文件

<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
   "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<!-- 标签库描述符 -->
<taglib xmlns="http://java.sun.com/JSP/TagLibraryDescriptor">
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>Simple Tags</short-name>
  <!--设置导入的路径名 -->
  <uri>/YX</uri>
  <!--添加标签 -->
  <tag>
    <!-- 设置标签名 -->
    <name>page</name>
    <!-- 绑定标签助手类 -->
    <tag-class>com.YX.Page.Tag.PageTag</tag-class>
    <!--设置标签内容信息类型 -->
    <body-content>JSP</body-content>
    <!--添加属性 -->
    <attribute>
      <!-- 设置属性名(与助手类定义的要一致 ) -->
      <name>pageBean</name>
      <!-- 设置是否为必要属性 -->
      <required>true</required>
      <!-- 设置是否接受El表达式 -->
      <rtexprvalue>true</rtexprvalue>
      <description>是对象数据用于输出页面</description>
    </attribute>
  </tag>
</taglib>

3.3 完善PageBean类

package com.YX.Page.untils;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.coyote.http11.Http11AprProtocol;
/**
 * 分页工具类
 * 用于实现分页显示的工具类
 *@author 君易--鑨
 */
public class PageBean {
  private int page = 1;// 页码
  private int rows = 10;// 页大小
  private int total = 0;// 总记录数
  private boolean pagination = true;// 是否分页
  /**
   * 计算最大页数的方法
   * @return int 
   */
  public int maxPage() {
    return this.total % this.rows==0?
        this.total / this.rows :
          this.total / this.rows+1;
  }
  /***
   * 下一页的方法
   * @return
   */
  public int nextPage() {
    return this.page<this.maxPage() ?
        this.page+1 : this.page;
  }
  /**
   * 上一页的方法
   * @return
   */
  public int prevPage() {
    return this.page > 1 ? this.page-1 : this.page;
  }
  public void setRequest(HttpServletRequest req) {
//    初始化默认查询的第几页数据
    this.setPage(req.getParameter("page"));
//    初始化默认显示数据量
    this.setRows(req.getParameter("rows"));
//    初始化下拉框
    this.setPagination(req.getParameter("pagination"));
//    保留上一次的URL
    this.setUrl(req.getRequestURL().toString());
//          保留携带的参数
    this.setParamMap(req.getParameterMap());
  }
  /**
   * 设置初始化是否使用分页的方法
   * @param pagination
   */
  private void setPagination(String pagination) {
    if (StringUtils.isNotBlank(pagination)) ;
    this.setPagination(!"false".equals(pagination));
  }
  /**
   * 设置初始化默认显示数据量的方法
   * @param rows
   */
  public void setRows(String rows) {
    if (StringUtils.isNotBlank(rows)) 
    this.setRows(Integer.valueOf(rows));
  }
  /**
   * 设置初始化默认查询的第几页数据的方法
   * @param page
   */
  public void setPage(String page) {
    if (StringUtils.isNotBlank(page)) 
    this.setPage(Integer.valueOf(page));
  }
  private String url;//保留上一次发送请求的地址
  private Map<String, String[]> paramMap;//保留上一次发送请求携带的参数
  public String getUrl() {
    return url;
  }
  public void setUrl(String url) {
    this.url = url;
  }
  public Map<String, String[]> getParamMap() {
    return paramMap;
  }
  public void setParamMap(Map<String, String[]> 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;
  }
  public void setPagination(boolean pagination) {
    this.pagination = pagination;
  }
  /**
   * 获得起始记录的下标
   * 
   * @return
   */
  public int getStartIndex() {
    return (this.page - 1) * this.rows;
  }
  @Override
  public String toString() {
    return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", pagination=" + pagination + "]";
  }
}

3.4 编写BookServlet类

package com.YX.Page;
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.YX.Page.Dao.BookDao;
import com.YX.Page.entity.Book;
import com.YX.Page.untils.PageBean;
@WebServlet("/book.action")
public class BookServlet extends HttpServlet {
  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    this.doPost(req, resp);
  }
  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//    @SuppressWarnings("unused")
//    String bname=req.getParameter("name");
//    Map<String, String[]> map=req.getParameterMap();
//    String url=req.getRequestURL().toString();
//    实例化分页工具类
    PageBean pageBean=new PageBean();
    pageBean.setRequest(req);
//    实例化Dao方法
    BookDao bookDao=new BookDao();
//    实例化实体对象
    Book book=new Book();
//    将搜索输入框中的内容传过去
    book.setBname(req.getParameter("bname"));
    try {
//      调用方法获取指定数据
      List<Book> books = bookDao.list(book, pageBean);
//      回显到页面
      req.setAttribute("books", books);
    } catch (Exception e) {
      e.printStackTrace();
    }
//    将pageBean传到页面上
    req.setAttribute("pageBean", pageBean);
//    回显的界面
    req.getRequestDispatcher("booklist.jsp").forward(req, resp);
  }
}

3.5 在jsp中运用自定义page标签

在这里插入<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!-- 导入自定义分页标签 -->
<%@taglib uri="/YX" prefix="yx" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link
  href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css"
  rel="stylesheet">
<script
  src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script>
<title>书籍列表</title>
<style type="text/css">
.page-item input {
  padding: 0;
  width: 40px;
  height: 100%;
  text-align: center;
  margin: 0 6px; 
}
.page-item input, .page-item b {
  line-height: 38px;
  float: left;
  font-weight: 400;
}
.page-item.go-input {
  margin: 0 10px;
}
</style>
</head>
<body>
  <form class="form-inline"
    action="${pageContext.request.contextPath }/book.action" method="post">
    <div class="form-group mb-2">
      <input type="text" class="form-control-plaintext" name="bname"
        placeholder="请输入书籍名称">
    </div>
    <button type="submit" class="btn btn-primary mb-2">查询</button>
  </form>
  <table class="table table-striped ">
    <thead>
      <tr>
        <th scope="col">书籍ID</th>
        <th scope="col">书籍名</th>
        <th scope="col">价格</th>
      </tr>
    </thead>
    <tbody>
    <c:forEach items="${books }" var="b">
      <tr>
        <td>${b.bid }</td>
        <td>${b.bname }</td>
        <td>${b.price }</td>
      </tr>
    </c:forEach>
    </tbody>
  </table>
    <yx:page pageBean="${pageBean }"></yx:page>
  <form action="" id="pageBeanForm" method="post">
    <input type="hidden" name="page">
  </form>
  <script type='text/javascript'>
    function gotoPage(page) {
      document.getElementById('pageBeanForm').page.value = page;
      document.getElementById('pageBeanForm').submit();
    }
    function skipPage() {
      var page = document.getElementById('skipPage').value;
      if (!page || isNaN(page) || parseInt(page) < 1
          || parseInt(page) > 1122) {
        alert('请输入1~N的数字');
        return;
      }
      gotoPage(page);
    }
  </script>
</body>
</html>代码片
注意事项:

使用模糊查询的话可能会用问题,例如在搜索框中输入“圣墟”,会出现中文字符乱码(如图所示)

点击搜索后的页面结果

处理办法:
编写EncodingFiterg(中文乱码处理类)
package com.YX.Page.untils;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 中文乱码处理类
 * 用于处理数据显示中文乱码
 * @author 君易--鑨
 *
 */
@WebFilter("*.action")
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();
    }
  }
}

3.6 完美的效果展示

3.6.1 没使用模糊查询

3.6.2 使用了模糊查询和分页功能

3.6.3 文件目录

4. 如何使用debug调试代码

4.1 理论步骤

  1. 打开Eclipse并导入你的项目。
  2. 找到你想要调试的Java类,然后在该类的左侧边栏中单击行号,添加一个断点。断点会在这个位置暂停代码执行。
  3. 单击Eclipse菜单栏上的Debug按钮(绿色的bug图标),或者使用快捷键Ctrl + F11来开始debug模式。
  4. 当程序进入断点所在的代码行时,程序执行会被暂停。此时,你可以查看变量值、观察堆栈跟踪和执行路径。
  5. 在debug模式下,有一些常用的按钮可以帮助你控制程序的执行:
  • Resume (F8): 继续执行程序直到下一个断点或代码结束。
  • Step Over (F6): 执行当前行并停在下一行。如果当前行包含方法调用,将执行整个方法并停在方法返回之后的下一行。
  • Step Into (F5): 如果当前行包含方法调用,将进入该方法并停在方法的第一行。
  • Step Return (F7): 从当前方法返回到调用当前方法的方法,并停在调用处的下一行。
  • Terminate (停止): 停止debug。在debug模式下,你可以通过点击停止按钮或者单击红色的关闭按钮来终止debug。
  1. 当程序在断点间经过时,你可以实时监视变量的值、检查条件的判断和程序的流程。

4.2 案例演示

4.2.1 debug启动项目

4.2.2 在将要调试的代码上打上断点

4.2.3 弹出窗口是否选择进入debug调试窗口

4.2.4 讲解

在Variables的窗口中可以看到当前类所有的变量,可以将鼠标悬浮在对应的变量查看相应的值;

结束语

希望我分享的东西能够给大家带来帮助,有做的不足的地方老铁可以私信我哦,希望进来浏览的老铁能够点赞和关注我,我每周都会与大家分享知识。


目录
相关文章
|
开发框架 关系型数据库 测试技术
J2EE之通用分页知识(上)(详解)
J2EE之通用分页知识(上)(详解)
80 0
|
开发框架 前端开发 Java
J2EE 通用分页01(超详细解析)
J2EE 通用分页01(超详细解析)
44 0
|
关系型数据库 MySQL
|
SQL 存储 搜索推荐
J2EE&通用分页01
J2EE&通用分页01
|
SQL 搜索推荐 数据库
|
前端开发 Java 测试技术
通用分页【上】
JUnit是流行的、开源的Java单元测试框架,它提供了一种简单而强大的方式来测试Java应用程序中的单元代码。JUnit测试通常涉及创建和运行测试用例,而测试用例是一组独立的测试步骤,用于验证代码是否按照预期工作。JUnit测试通常分为以下四个步骤:定义测试用例:定义每个测试方法所需的输入参数以及期望的输出结果;编写测试代码:编写测试方法并使用断言(Assertion)来验证代码是否按照预期工作;运行测试用例:通常使用JUnit测试浏览器或者其他测试工具来运行测试用例;查看测试结果。
|
前端开发 数据管理 Java
通用分页(下)
通用分页(下)
56 0
|
Java 数据库
通用分页之详解】
通用分页之详解】
50 1
通用分页(后台分页)
通用分页(后台分页)
64 0
|
前端开发
通用分页02(前台分页)
通用分页02(前台分页)
65 0