07-EL&JSTL

EL 表达式

最初出现的目的是为了取代 JSP 页面中的 "脚本表达式<%= %>",格式:${...}。但随着 EL 的发展,其功能已不限于此。

获取数据

  • 获取常量:字符串、数字、布尔类型
    ${"root" }
    ${12345 }
    ${true }
    
  • 获取域中的变量
    • 如果表达式中写的是一个变量名,则 EL 会调用 pageContext 的 findAttriubte(),在 4 大作用域中以给定的名字找对应的属性值,然后进行输出
    • 如果四个域中都找不到,则什么都不输出
  • 获取数组中的数据
    <%
        String[] names = {"A","B","C","D"};
        pageContext.setAttribute("names", names);
    %>
    ${names[0] }
    
  • 获取集合中的数据
    • 获取 Collection 中的数据
      <%
          List<String> list = new ArrayList<String>();
          list.add("aaa");
          list.add("bbb");
          list.add("ccc");
          pageContext.setAttribute("list", list);
      %>
      ${list[2] }
      
    • 获取 Map 中的数据
      • map["key"]map.key 在使用上的不同:当 key 是数字或者包含特殊字符 -/.,只能用 map["key"]
      • 注意如下这二者的差别
        07-EL&JSTL
  • 获取 JavaBean 的属性
    • ${obj.xxx} 这句话的底层其实是 EL 调用了 obj 的 getXxx()
    • 在写路径的时候,同理可得:${pageContext.request.contextPath}

执行运算

  • 算术运算
    • + | - | * | /
    • 如果有非数字参与算术运算,EL 表达式会试图将非数字转换为数字后参与运算
      ${1+‘1‘} → 2
      ${1+‘a‘} → 抛异常
      
  • 比较运算
    <	lt
    >	gt
    <=	le
    >=	ge
    !=	ne
    ==	eq
    --------
    ${1 eq 1}、${3 ge 2}
    
  • 逻辑运算
    &&	and
    ||	or
    !	not
    --------
    ${not (3>2) and 1<2 or 10>3} => false
    
  • 三元运算符:${7>6 ? "yes" : "no"}
  • empty 运算符:判断一个对象是否为 null / 字符串是否为空字符串 / 集合内容是否为空 / 域中是否没有任何属性

获取常用开发对象

EL 中内置了 11 个对象,这些对象不需要提前定义就可以直接使用

  1. pageContext:可以很方便的获取 JSP 页面中的 9 大隐式对象;如 ${pageContext.request|session|...}
  2. pageScope:page域中属性组成的 Map
  3. requestScope:request域中属性组成的 Map
  4. sessionScope:session域中属性组成的 Map
  5. applicationScope:application域中属性组成的 Map
  6. param:所有请求参数组成的 Map<String,String>
  7. paramValues:所有请求参数组成的 Map<String,String[]>;如 ${paramValues.hobbies[2]}
  8. header:所有请求头组成的 Map<String,String>
  9. headerValues:所有请求头组成的 Map<String,String[]>
  10. cookie:所有 Cookie 信息组成的 Map<String,Cookie>;如 ${cookie.JSESSIONID.value}
  11. initParam:web 应用的所有初始化参数组成的 Map<String,String>;如 ${initParam.name1}
    《web.xml》
    <context-param>
        <param-name>name1</param-name>
        <param-value>value1</param-value>
    </context-param>
    

调用方法

不是任意方法都可以被调用,需要满足如下 3 个条件:

  1. 静态方法
  2. 写一个 tld 文件,在其中对要被调用的静态方法进行描述
  3. 用 taglib 指令将 tld 文件引入当前 JSP 页面,从而在 JSP 页面中调用描述好的方法

举例:对给定的 URL 进行 URL 编码

ELFunc.java

public class ELFunc {
    public static String encode(String str, String encode) {
        try {
            return URLEncoder.encode(str, encode);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

MyELFunc.tld(放在 WEB-INF 目录下)

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
    <tlib-version>1.0</tlib-version>
    <short-name>MyELFunc</short-name>
    <uri>http://www.nuist.edu.cn/MyELFunc</uri>
    <function>
        <name>urlEncode</name>
        <function-class>cn.edu.nuist.util.ELFunc</function-class>
        <function-signature>
            java.lang.String encode(java.lang.String, java.lang.String)
        </function-signature>
    </function>
</taglib>

el3.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://www.nuist.edu.cn/MyELFunc" prefix="MyELFunc" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title>使用EL表达式调用方法</title>
    </head>
    <body>
        调用自定义函数:${MyELFunc:urlEncode("徐州","utf-8") }
        调用JSTL函数库中的函数:${fn:toLowerCase("JAFIOjifeoFIAWfjiof") }
    </body>
</html>

JSTL 中提供了一套 EL 自定义函数,这些函数包含了 JSP 页面制作者经常要用到的字符串操作。例如, fn:toLowerCase 将字符串中的字符变为小写,fn:indexOf 返回一个指定字符串在另一个字符串中第一次出现的索引位置。JSTL 中提供的 EL 自定义函数必须在 EL 表达式中使用。

  1. fn:toLowerCase
  2. fn:toUpperCase
  3. fn:trim
  4. fn:escapeXml
  5. fn:length
  6. fn:split
  7. fn:join
  8. fn:indexOf
  9. fn:contains
  10. fn:containsIgnoreCase
  11. fn:startsWith
  12. fn:startsWith
  13. fn:replace
  14. fn:substring
  15. fn:substringAfter
  16. fn:substringBefore

JSTL 标签库

全称:JavaServer Pages Standard Tag Library。提供给 Java Web 开发人员一个标准通用的标签函数库和 EL 配合来取代传统直接在页面上嵌入 Java 程序(Scripting)的做法,以提高程序可读性、维护性和方便性。

导入 [核心标签库c]<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

  • <c:out>:标签用于输出一段文本内容到 pageContext 对象当前保存的 out 对象中
    07-EL&JSTL
    • 输出常量:<c:out value="<hhhh>"></c:out>
    • 输出变量:<c:out value="${name }"></c:out>
    • 输出默认值:<c:out value="${addr }" default="XZ"></c:out>
    • 输出转义字符:<c:out value="<a href=‘#‘>xxx</a>"></c:out>
  • <c:set>
    07-EL&JSTL
    • 设置/修改域中的属性值 (默认 page 域)
      <c:set scope="request" var="name" value="金敏喜"></c:set>
    • 设置/修改域中 Map 的值
      <%
          Map<String, String> map = new HashMap<String, String>();
          pageContext.setAttribute("map", map);
      %>
      <h4>target属性的值是Map对象,property属性表示该Map对象的某个key</h4>
      <c:set target="${map }" property="cellphone" value="10086"></c:set>
      ${map.cellphone }
      
    • 设置/修改域中 JavaBean 的值
      <%
          Person p = new Person();
          pageContext.setAttribute("p", p);
      %>
      <h4>target属性的值是JavaBean对象,property属性表示JavaBean对象的属性</h4>
      <c:set target="${p }" property="name" value="玉珠"></c:set>
      ${p.name }
      
  • <c:remove>
    • 删除域中属性(如果不写 scope 属性,会把 4 个域中叫 var 的属性都删除)
    • 格式:<c:remove var="varName" [scope="{page|request|session|application}"] />
  • <c:catch>
    • 用于捕获嵌套在标签体中的内容抛出的异常,var 属性用于标识 <c:catch> 标签捕获的异常对象,它将保存在 page 域中
    • 示例
      <c:catch var="myex" >
          <%
              10/0;
          %>
      </c:catch>
      异常:<c:out value="${myex}" />  ${myex}<br />
      异常 myex.getMessage:<c:out value="${myex.message}" /><br />
      异常 myex.getCause:<c:out value="${myex.cause}" /><br />
      异常 myex.getStackTrace:<c:out value="${myex.stackTrace}" />
      
  • <c:if>
    07-EL&JSTL
    • 用来构造简单的“if-then”结构的条件表达式
    • 例如:<c:if test="${6<7 }">you will.</c:if>
  • <c:choose>
    • <c:choose> 标签用于指定多个条件选择的组合边界,它必须与 <c:when><c:otherwise> 标签一起使用。使用 <c:choose><c:when><c:otherwise> 三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。
    • 示例
      <%
          int day = 1;
          pageContext.setAttribute("day", day);
      %>
      <c:choose>
          <c:when test="${day == 1 }">周一</c:when>
          <c:when test="${day == 2 }">周二</c:when>
          <c:when test="${day == 3 }">周三</c:when>
          <c:when test="${day == 4 }">周四</c:when>
          <c:when test="${day == 5 }">周五</c:when>
          <c:otherwise>周末</c:otherwise>
      </c:choose>
      
  • <c:forEach>
    07-EL&JSTL
    <h1>遍历数组中的数据</h1>
    <%
        String[] cities = {"北京", "上海", "广州", "深圳"};
        pageContext.setAttribute("cities", cities);
    %>
    <c:forEach items="${cities }" var="c">
        ${c }
    </c:forEach>
    <hr/>
    
    <h1>遍历集合中的数据</h1>
    <%
        List<String> list = new ArrayList<String>();
        list.add("英国");
        list.add("法国");
        list.add("德国");
        list.add("荷兰");
        pageContext.setAttribute("list", list);
    %>
    <c:forEach items="${list }" var="country">
        ${country }
    </c:forEach>
    <hr/>
    
    <h1>遍历Map中的数据</h1>
    <%
        Map<String,String> map = new HashMap<String, String>();
        map.put("aaa", "111");
        map.put("bbb", "222");
        map.put("ccc", "333");
        map.put("ddd", "444");
        pageContext.setAttribute("map", map);
    %>
    <c:forEach items="${map }" var="entry">
        ${entry.key } —— ${entry.value }
    </c:forEach>
    <hr/>
    
    <h1>循环执行指定的内容若干次</h1>
    <c:forEach begin="0" end="10" step="2" var="i">
        ${i }
    </c:forEach>
    <hr/>
    
    <h1>varStatus 属性:遍历10~100的偶数, 如果"数字所在的位置"是3的倍数, 显示成红色</h1>
    <c:forEach begin="10" end="100" step="2" var="i" varStatus="stat">
        <c:if test="${stat.count % 3 == 0 }">
            <font color="red">${i }</font>
        </c:if>
        <c:if test="${stat.count % 3 != 0 }">
            <font color="blue">${i }</font>
        </c:if>
    </c:forEach>
    
  • <c:forTokens>
    07-EL&JSTL
    <c:forTokens items="www.nuist.edu.cn" delims="." var="str">
        ${str } <br/>
    </c:forTokens>
    
  • <c:import>:请求包含
    07-EL&JSTL
  • <c:redirect>:请求重定向
    07-EL&JSTL
  • <c:url>
    • 用于在 JSP 页面中构造一个 URL 地址,其主要目的是实现 URL 重写(URL 重写就是将会话标识号以参数形式附加在URL地址后面)
    • 示例
      <c:url value="/index.jsp" context="${pageContext.request.contextPath }"
          var="url" scope="page"></c:url>
      <a href="${url }"></a>
      
  • <c:param>:配合上述三个标签使用;示例:<c:param name="name" value="value" />

自定义标签

07-EL&JSTL

传统标签

生命周期

第一次被使用时创建出来, 后续一直驻留在内存中, 为后续请求服务

开发步骤

以显示客户机 IP 为例

  • 写一个类实现 javax.servlet.jsp.tagext.Tag<I>
    public class ShowIPTag implements Tag{
        private PageContext pc;
    
        public void setPageContext(PageContext pc) {
            // 1.
            this.pc = pc;
        }
    
        public void setParent(Tag t) {
            // 2. 传入的是当前标签的"父标签", 没有则传null
        }
    
        public Tag getParent() {
            return null;
        }
    
        public int doStartTag() throws JspException {
            // 3.
            try {
                pc.getOut().write(pc.getRequest().getRemoteAddr());
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
            return 0;
        }
    
        public int doEndTag() throws JspException {
            // 4.
            return 0;
        }
    
        public void release() {}
    }
    
  • 创建一个 tld 文件,放在 WEB-INF 目录下,描述写好的类
    <?xml version="1.0" encoding="UTF-8"?>
    <taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
            http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
        <tlib-version>1.0</tlib-version>
        <short-name>MyTag</short-name>
        <uri>http://www.nuist.edu.cn/MyTag</uri>
        <tag>
            <name>showip</name>
            <tag-class>cn.edu.nuist.tag.ShowIPTag</tag-class>
            <body-content>empty</body-content>
        </tag>
    </taglib>
    
    • JSP:任意内容 (简单标签不支持)
    • Scriptless:任意 JSP 内容,不包括 Java 代码
    • empty:该标签是个自闭标签
    • tagdependent:标签体是给后台用的 (没人用)
  • 在 JSP 页面中
    • 引入 tld 文件:<%@ taglib uri="http://www.nuist.edu.cn/MyTag" prefix="MyTag" %>
    • 在 JSP 页面中使用"自定义标签":<MyTag:showip/>

简单标签

开发步骤

  • 写一个类实现 SimpleTag<I> / 继承它的默认实现类 SimpleTagSupport
  • 写一个 tld 文件,描述写好的类
  • 在 JSP 页面中,引入 tld 文件,就可以在 JSP 页面中使用"自定义标签"了

执行过程

当 JSP 在执行的过程中,每当遇到一个简单标签时,都会创建一个处理类对象(如下步骤是实现接口方式的;若是继承默认实现类方式,则父类会把前几步替你做了,你就只需要提供属性声明、属性对应 setXxx()doTag() 即可)

  • 传入当前 JSP 页面的 PageContext 对象 setJspContext(JspContext pc)
  • 如果当前标签有父标签,则调用 setParent(JspTag parent) 将父标签传入;如果没有父标签,则这个方法不会被调用
  • 如果该标签具有属性,调用属性的 setXxx() 将属性的值传入
  • 如果当前标签具有标签体,则会调用 setJspBody(JspFragment jspBody) 将封装了标签体信息的 JspFragment 传入;如果没有标签体,则这个方法不会被调用
  • 最后,调用 doTag(),在这个方法里我们可以书写处理【标签事件】的 Java 代码
  • 当自定义标签执行完成后,自定义简单标签对象就销毁掉了
  • 为自定义标签增加属性
  • 在标签处理类中增加一个 JavaBean 属性,这个属性就是要增加的标签的属性,并对外提供 setXxx()
  • 在 tld 文件中这个标签的描述中描述一下该属性
    <attribute>
        <name>标签的属性名必须与对应的标签类的成员变量名一致</name>
        <required>是否是必须的属性</required>
        <rtexprvalue>是否支持EL表达式</rtexprvalue>
        <type>属性的数据类型</type>
    </attribute>
    

案例

  • 实例1:显示客户机 IP 功能(实现接口方式)
    public class SimpleShowIPTag implements SimpleTag {
    
        private JspContext pc;
    
        public void doTag() throws JspException, IOException {
            PageContext pcx = (PageContext) pc;
            pcx.getOut().write(pcx.getRequest().getRemoteAddr());
        }
    
        public void setParent(JspTag parent) {}
    
        public JspTag getParent() {
            return null;
        }
    
        public void setJspContext(JspContext pc) {
            this.pc = pc;
        }
    
        public void setJspBody(JspFragment jspBody) {}
    
    }
    
  • 实例2:没啥目的,纯粹为了展示标签类里的功能(继承类方式)
    public class DemoSimpleTag extends SimpleTagSupport {
        // 成员属性对应自定义标签的属性
        private int times;
    
        // 对外必须提供 setXxx()
        public void setTimes(int times) {
            this.times = times;
        }
    
        @Override
        public void doTag() throws JspException, IOException {
            // 功能1: 控制标签体是否执行
                // 不执行 —— 什么都不做,标签体就不会执行
                // 执行 —— 调用封装着标签体的 JspFragment 对象的 invoke()
                    // 参数可以传 null, 如果传 null 底层还是会打给 out 缓冲区
                    // getJspBody().invoke(getJspContext().getOut());
    
            // 功能2: 控制标签之后的内容是否执行
                // 执行 —— 什么都不做
                // 不执行 —— 抛出SkipPageException
                    // throw new SkipPageException();
    
            // 功能3: 控制标签体重复执行
            for(int i = 0; i < times; i++)
                getJspBody().invoke(null);
    
            // 功能4: 修改标签体后进行输出
            /*
            StringWriter writer = new StringWriter(); // 目的地为String 的一个字符输出流
            JspFragment jspBody = getJspBody();
            jspBody.invoke(writer);
            String str = writer.toString();
            str = str.toUpperCase();
            getJspContext().getOut().write(str);
            */
        }
    }
    
  • 对应到 MyTag.tld
    <tag>
        <name>simpleshowip</name>
        <tag-class>cn.edu.nuist.simpletag.SimpleShowIPTag</tag-class>
        <body-content>empty</body-content>
    </tag>
    <tag>
        <name>demosimpletag</name>
        <tag-class>cn.edu.nuist.simpletag.DemoSimpleTag</tag-class>
        <body-content>scriptless</body-content>
        <attribute>
            <name>times</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>int</type>
        </attribute>
    </tag>
    

案例

If 标签

public class IfTag extends SimpleTagSupport {
    private boolean test;

    public void setTest(boolean test) {
        this.test = test;
    }

    @Override
    public void doTag() throws JspException, IOException {
        if(test) getJspBody().invoke(null);
    }
}
<tag>
    <name>if</name>
    <tag-class>cn.edu.nuist.simpletag.IfTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <name>test</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
        <type>boolean</type>
    </attribute>
</tag>

防盗链标签

public class RefTag extends SimpleTagSupport {
    @Override
    public void doTag() throws JspException, IOException {
        PageContext pC = (PageContext) getJspContext();
        HttpServletRequest request = (HttpServletRequest) pC.getRequest();
        HttpServletResponse response = (HttpServletResponse) pC.getResponse();
        String ref= request.getHeader("referer");
        if(ref == null || "".equals(ref) || !ref.startsWith("http://localhost")) {
            response.sendRedirect(request.getContextPath() + "/index.jsp");
            return;
        }
    }
}
<tag>
    <name>ref</name>
    <tag-class>cn.edu.nuist.simpletag.RefTag</tag-class>
    <body-content>empty</body-content>
</tag>

转义标签

public class TranHTMLTag extends SimpleTagSupport {
    @Override
    public void doTag() throws JspException, IOException {
        StringWriter writer = new StringWriter();
        getJspBody().invoke(writer);
        String str = writer.toString();
        // 转义
        str = filter(str);
        getJspContext().getOut().write(str);
    }

    private String filter(String message) {
        if (message == null) return (null);

        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuffer result = new StringBuffer(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
                case ‘<‘:
                    result.append("&lt;");
                    break;
                case ‘>‘:
                    result.append("&gt;");
                    break;
                case ‘&‘:
                    result.append("&amp;");
                    break;
                case ‘"‘:
                    result.append("&quot;");
                    break;
                default:
                    result.append(content[i]);
            }
        }
        return (result.toString());
    }
}
<tag>
    <name>tran</name>
    <tag-class>cn.edu.nuist.simpletag.TranHTMLTag</tag-class>
    <body-content>scriptless</body-content>
</tag>

分页查询功能

功能分析

  • 在 index.jsp 提供客户信息列表页面的超链接,超链接尾部记得加上 "?thisPage=1"
  • PageCustServlet
    • 获取要访问的页码以及每页显示多少条记录
    • 调用service中分页查询客户的方法
    • 将查到的结果存入 request 域带到 pageList.jsp 做显示
  • 提供一个JavaBean —— Page,属性如下:
    private int thisPage;
    private int rowPerPage;
    private int countRow;
    private int countPage;
    private int firstPage;
    private int lastPage;
    private int prePage;
    private int nextPage;
    private List<Cust> list;
    
  • 效果:共 xxx 条记录 共 xx 页 首页 上一页 1 2 3 4 5 下一页 尾页

分页技术

逻辑分页

  • 原理
    • 在 SQL 查询时,先从 DB 检索出所有数据的结果集
    • 在程序内,通过逻辑语句获取分页所需要的数据
    • 如:检索 11-20 条 userList.subList(10,20);
  • 缺点
    • 如果有 10000 条记录呢,也全部放在内存中吗
    • 如果数据有变动呢,集合中也反应不出来
  • 适用情景: 在基本不会变动、记录数少的情况下使用

物理分页

  • 原理
    • 在SQL查询时,从DB只检索分页需要的数据
    • 通常不同的DB有着不同的物理分页语句
  • MySQL:采用 limit 关键字
    • 如:检索 11-20 条 SELECT * FROM user LIMIT 10,10;
    • param1:索引(从0开始);param2:查取多少条

代码实现

  • CustDaoImpl
    public List<Cust> getCustByScope(int from, int count) {
        String sql = "select * from customer limit ?,?";
        QueryRunner runner = new QueryRunner(DaoUtils.getSource());
        try {
            return runner.query(sql, new BeanListHandler<Cust>(Cust.class),from,count);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    
  • CustServiceImpl
    public Page pageCust(int thisPage, int rowPerPage) {
        Page page = new Page();
        page.setThisPage(thisPage);
        page.setRowPerPage(rowPerPage);
        int countRow = dao.getCountRow();
        page.setCountRow(countRow);
        int countPage = countRow%rowPerPage==0 ? countRow/rowPerPage : countRow/rowPerPage+1;
        page.setCountPage(countPage);
        page.setFirstPage(1);
        page.setLastPage(countPage);
        page.setPrePage(thisPage==1 ? 1 : thisPage-1);
        page.setNextPage(thisPage==countPage ? countPage : thisPage+1);
        int index = (thisPage-1) * rowPerPage;
        page.setList(dao.getCustByScope(index, rowPerPage));
        return page;
    }
    
  • PageCustServlet
    public class PageCustServlet extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            CustService service = BasicFactory.getFactory().getInstance(CustService.class);
            // 获取当前要显示的页
            int thisPage = Integer.parseInt(request.getParameter("thisPage"));
            // 每页记录数就设成10
            int rowPerPage = 10;
            // 调用 service 中分页查询客户的方法
            Page page = service.pageCust(thisPage,rowPerPage);
            // 存入 request 域中,带到 pageCust.jsp 做显示
            request.setAttribute("page", page);
            request.getRequestDispatcher("/pageCust.jsp").forward(request, response);
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    }
    
  • pageList.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>
            <meta http-equiv="pragma" content="no-cache">
            <meta http-equiv="cache-control" content="no-cache">
            <meta http-equiv="expires" content="0">
            <script type="text/javascript">
                function changePage(obj) {
                    if(isNaN(obj.value)) {
                        alert("页码必须是数字!");
                        obj.value = "${page.thisPage}";
                        return;
                    } else if(obj.value <= 0 || obj.value > ${page.countPage}) {
                        alert("页码必须在有效范围内!");
                        obj.value="${page.thisPage}";
                        return;
                    } else {
                        window.location.href = "${pageContext.request.contextPath}/servlet/PageCustServlet?thisPage=" + obj.value;
                    }
                }
            </script>
        </head>
    <body>
        <div align="center">
        <h1>分页查询</h1>
        <table border="1">
            <tr>
                <th>客户姓名</th>
                <th>客户性别</th>
                <th>出生日期</th>
                <th>手机号码</th>
                <th>电子邮箱</th>
                <th>客户爱好</th>
                <th>客户类型</th>
                <th>描述信息</th>
            </tr>
            <c:forEach items="${requestScope.page.list }" var="cust">
            <tr>
                <td><c:out value="${cust.name }"/></td>
                <td><c:out value="${cust.gender }"/></td>
                <td><c:out value="${cust.birthday }"/></td>
                <td><c:out value="${cust.cellphone }"/></td>
                <td><c:out value="${cust.email }"/></td>
                <td><c:out value="${cust.preference }"/></td>
                <td><c:out value="${cust.type }"/></td>
                <td><c:out value="${cust.description }"/></td>
            </tr>
        </c:forEach>
        </table>
        共${page.countRow }条记录
        共${page.countPage }页
        <a href="${pageContext.request.contextPath }/servlet/PageCustServlet?thisPage=${page.firstPage}">首页</a>
        <a href="${pageContext.request.contextPath }/servlet/PageCustServlet?thisPage=${page.prePage}">上一页</a>
        <!-- 分页逻辑开始 -->
        <c:if test="${page.countPage <= 5 }">
            <c:set var="begin" value="1" scope="page"/>
            <c:set var="end" value="${page.countPage }" scope="page"/>
        </c:if>
        <c:if test="${page.countPage > 5 }">
            <c:choose>
                <c:when test="${page.thisPage <= 3 }">
                    <c:set var="begin" value="1" scope="page"/>
                    <c:set var="end" value="5" scope="page"/>
                </c:when>
                <c:when test="${page.thisPage >= page.countPage - 2 }">
                    <c:set var="begin" value="${page.countPage - 4 }" scope="page"/>
                    <c:set var="end" value="${page.countPage }" scope="page"/>
                </c:when>
                <c:otherwise>
                    <c:set var="begin" value="${page.thisPage - 2 }" scope="page"/>
                    <c:set var="end" value="${page.thisPage + 2 }" scope="page"/>
                </c:otherwise>
            </c:choose>
        </c:if>
        <c:forEach begin="${begin }" end="${end }" var="i">
            <c:if test="${page.thisPage != i }">
            <a href="${pageContext.request.contextPath }/servlet/PageCustServlet?thisPage=${i}">${i }</a>
            </c:if>
            <c:if test="${page.thisPage == i }">${i }</c:if>
        </c:forEach>
        <!-- 分页逻辑结束 -->
        <a href="${pageContext.request.contextPath }/servlet/PageCustServlet?thisPage=${page.nextPage}">下一页</a>
        <a href="${pageContext.request.contextPath }/servlet/PageCustServlet?thisPage=${page.lastPage}">尾页</a>
        跳到 <input type="text" value="${page.thisPage }" style="width: 50px;" onchange="changePage(this)"> 页
        </div>
        </body>
    </html>
    

07-EL&JSTL

上一篇:Kubernetes--Volume存储卷实践


下一篇:Kubernetes K8S 基本概述、设计架构和设计理念